Diabetes Prevalence Across Geographically Diverse States in the US

1 Preliminaries

1.1 R Packages

library(janitor)
library(naniar)
library(tidyverse)
library(broom)
library(equatiomatic)
library(kableExtra)
library(patchwork)
library(glue)

1.2 Data Ingest

To begin, we read the data from a csv format into a tibble within R, skipping over the row containing data for the entire US and keeping only counties that are actually counties (ranked).

chr_2022_raw <- read_csv("analytic_data2022.csv", skip = 1) |> filter(county_ranked == 1)

2 Data Development

2.1 State Selection

Next is the selection of states to investigate - I’ve selected Arizona, Georgia, Massachusetts, Ohio, and Washington. I’ve picked these states because I wanted to get a good distribution of areas across the US, so each state location-wise is quite different than the others. Furthermore, I picked states that had similar populations, as all five states ranked between 7 and 15 in terms of population. The total amount of counties was 315, falling within the range needed, with Arizona having 15, Georgia having 159, Massachusetts having 14, Ohio having 88, and Washington having 39 counties respectively.

# select states
chr_2022 <- chr_2022_raw |>
  filter(state == "OH" | state == "GA" | state == "MA" | state == "WA" | state == "AZ")

# counties by state
chr_2022 |> tabyl(state)
 state   n    percent
    AZ  15 0.04761905
    GA 159 0.50476190
    MA  14 0.04444444
    OH  88 0.27936508
    WA  39 0.12380952
# tibble dimensions
dim(chr_2022)
[1] 315 725

2.2 Variable Selection

Along with the four required variables (fipscode, county, state, and county_ranked), we had to select five more variables. We selected diabetes prevalence (v060_rawvalue) to be the outcome variable, median income (v063_rawvalue) and adult smoking (v009_rawvalue) to be quantitative variables, excessive drinking (v049_rawvalue) to be the binary variable, and limited access to healthy foods to be the categorical variable (v083_rawvalue). Diabetes prevalence was chosen as obesity has been significantly increasing recently around the world, particularly in the US. Median income was chosen as it has been well documented that people with lower income are at higher risk of having diabetes. Adult smoking was chosen because similar to income, it’s been found to increase one’s chances of having diabetes. Excessive drinking was selected as it also has been found to increase the risk of diabetes. Lastly, limited access to healthy foods was selected as if one didn’t have access to healthy foods, they would be more prone to buying unhealthy ones that would lead to higher chances of obesity and diabetes. Each variable had to be adjusted according (scaling wise) to become an appropriate value, such as a percent. For excessive drinking, the cutoff chosen between a 0 and 1 value was the mean excessive drinking percentage. For limited access to healthy foods, each category was evenly split as to how many counties were in each.

# select variables
chr_2022 <- chr_2022 |>
  select(fipscode, county, state, county_ranked, v060_rawvalue, v063_rawvalue, v009_rawvalue, 
         v049_rawvalue, v083_rawvalue) |>
  rename(diabetes_prevalence = v060_rawvalue, 
         median_income = v063_rawvalue,
         adult_smoking = v009_rawvalue,
         excessive_drinking = v049_rawvalue,
         limited_access_healthy_foods = v083_rawvalue) |>
  mutate(diabetes_prevalence = diabetes_prevalence * 100,
         median_income = median_income / 1000,
         adult_smoking = adult_smoking * 100,
         excessive_drinking = excessive_drinking * 100,
         limited_access_healthy_foods = limited_access_healthy_foods * 100)

2.3 Variables to Factors

For variable 4 (excessive_drinking), we made it a binary variable rather than keep it quantitative. To split values into two distinct categories, the mean value was used as a cutoff, with values of percentages below the mean set to 0, and otherwise set to 1. The 5th variable (limited access to healthy foods) was also made categorical, however this time it’s multi-categorical rather than binary. To achieve this and ensure that all the categories would have an appropriate amount of values, we used the cut2 function, which split up values into categories such that each category has the same amount of values. After finding what the intervals were for each category, each one was refactored into numerical values, ranging from 0-5, albeit with some NA values that weren’t factored in.

chr_2022 <- chr_2022 |>
    mutate(fipscode = str_pad(fipscode, 5, pad = "0"),
           state = factor(state))

# make excessive_drinking a binary variable
chr_2022 <- chr_2022 |>
    mutate(excessive_drinking_cat = case_when(
                   excessive_drinking < mean(excessive_drinking) ~ 0, TRUE ~ 1),
           excessive_drinking_cat = factor(excessive_drinking_cat))

# make limited access to healthy foods categorical
chr_2022 <- chr_2022 |>
    mutate(limited_healthy_cat = factor(Hmisc::cut2(limited_access_healthy_foods, g = 5)))

# see intervals for categories
unique(chr_2022["limited_healthy_cat"])
# A tibble: 6 × 1
  limited_healthy_cat
  <fct>              
1 [12.51,47.43]      
2 [ 8.39,12.51)      
3 [ 5.51, 8.39)      
4 [ 0.00, 2.76)      
5 [ 2.76, 5.51)      
6 <NA>               
# recode factor values
chr_2022 <- chr_2022 |>
    mutate(limited_healthy_cat = fct_recode(limited_healthy_cat,
                                            "lowest" = "[ 0.00, 2.76)",
                                            "low" = "[ 2.76, 5.51)",
                                            "middle" = "[ 5.51, 8.39)",
                                            "high" = "[ 8.39,12.51)",
                                            "highest" = "[12.51,47.43]"))

2.3.1 Checking value distributions

chr_2022 |> tabyl(excessive_drinking_cat)
 excessive_drinking_cat   n   percent
                      0 165 0.5238095
                      1 150 0.4761905
chr_2022 |> tabyl(limited_healthy_cat)
 limited_healthy_cat  n    percent valid_percent
              lowest 62 0.19682540           0.2
                 low 62 0.19682540           0.2
              middle 62 0.19682540           0.2
                high 62 0.19682540           0.2
             highest 62 0.19682540           0.2
                <NA>  5 0.01587302            NA
# get structure
str(chr_2022)
tibble [315 × 11] (S3: tbl_df/tbl/data.frame)
 $ fipscode                    : chr [1:315] "04001" "04003" "04005" "04007" ...
 $ county                      : chr [1:315] "Apache County" "Cochise County" "Coconino County" "Gila County" ...
 $ state                       : Factor w/ 5 levels "AZ","GA","MA",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ county_ranked               : num [1:315] 1 1 1 1 1 1 1 1 1 1 ...
 $ diabetes_prevalence         : num [1:315] 15.7 11.3 9.4 11.2 11.9 11.5 12.4 10.2 10.2 13.6 ...
 $ median_income               : num [1:315] 36.3 51.2 57.1 49.3 55.4 ...
 $ adult_smoking               : num [1:315] 23.9 17.6 18.1 19.8 17.4 15.2 19.5 14.3 21 20.7 ...
 $ excessive_drinking          : num [1:315] 15.3 18.3 20.5 21.5 18.5 ...
 $ limited_access_healthy_foods: num [1:315] 35.3 15.6 13.3 11 15.7 ...
 $ excessive_drinking_cat      : Factor w/ 2 levels "0","1": 1 2 2 2 2 2 1 1 2 1 ...
 $ limited_healthy_cat         : Factor w/ 5 levels "lowest","low",..: 5 5 5 4 5 5 5 3 5 5 ...

2.4 Revising Order of Variables

chr_2022 <- chr_2022 |> relocate(county_ranked, .after = last_col())

2.5 Three Important Checks

  1. 75% completeness of data for each state
  2. Raw versions of variables must have at least 10 distinct non-missing values
  3. 10 counties in each category for categorical variables
# check completeness (1)
chr_2022 |> miss_var_summary()
# A tibble: 11 × 3
   variable                     n_miss pct_miss
   <chr>                         <int>    <dbl>
 1 limited_access_healthy_foods      5     1.59
 2 limited_healthy_cat               5     1.59
 3 fipscode                          0     0   
 4 county                            0     0   
 5 state                             0     0   
 6 diabetes_prevalence               0     0   
 7 median_income                     0     0   
 8 adult_smoking                     0     0   
 9 excessive_drinking                0     0   
10 excessive_drinking_cat            0     0   
11 county_ranked                     0     0   
# ensure no issues
mosaic::favstats(limited_access_healthy_foods ~ state, data = chr_2022) |>
  select(state, n, missing) |>
  mutate(pct_available = 100 * (n - missing) / n) |>
  kable()
Registered S3 method overwritten by 'mosaic':
  method                           from   
  fortify.SpatialPolygonsDataFrame ggplot2
state n missing pct_available
AZ 15 0 100.00000
GA 155 4 97.41935
MA 14 0 100.00000
OH 88 0 100.00000
WA 38 1 97.36842
# check distincts (2)
chr_2022 |> summarize(across(diabetes_prevalence:limited_access_healthy_foods, 
                             ~n_distinct(.)))
# A tibble: 1 × 5
  diabetes_prevalence median_income adult_smoking excessive_drinking limited_a…¹
                <int>         <int>         <int>              <int>       <int>
1                  93           314           142                315         311
# … with abbreviated variable name ¹​limited_access_healthy_foods
# check amount of counties for each categorical variable (3)
chr_2022 |> tabyl(excessive_drinking_cat)
 excessive_drinking_cat   n   percent
                      0 165 0.5238095
                      1 150 0.4761905
chr_2022 |> tabyl(limited_healthy_cat)
 limited_healthy_cat  n    percent valid_percent
              lowest 62 0.19682540           0.2
                 low 62 0.19682540           0.2
              middle 62 0.19682540           0.2
                high 62 0.19682540           0.2
             highest 62 0.19682540           0.2
                <NA>  5 0.01587302            NA

3 Our Analytic Tibble

3.1 Printing and Summarizing

We have to demonstrate a few things about our data. This includes printing the tibble, showing that each quantitative variable has at least 15 distinct values, and that each state has at least 75% completeness of data.

chr_2022
# A tibble: 315 × 11
   fipscode county state diabe…¹ media…² adult…³ exces…⁴ limit…⁵ exces…⁶ limit…⁷
   <chr>    <chr>  <fct>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl> <fct>   <fct>  
 1 04001    Apach… AZ       15.7    36.3    23.9    15.3   35.3  0       highest
 2 04003    Cochi… AZ       11.3    51.2    17.6    18.3   15.6  1       highest
 3 04005    Cocon… AZ        9.4    57.1    18.1    20.5   13.3  1       highest
 4 04007    Gila … AZ       11.2    49.3    19.8    21.5   11.0  1       high   
 5 04009    Graha… AZ       11.9    55.4    17.4    18.5   15.7  1       highest
 6 04011    Green… AZ       11.5    67.5    15.2    19.5   14.0  1       highest
 7 04012    La Pa… AZ       12.4    41.6    19.5    17.1   26.5  0       highest
 8 04013    Maric… AZ       10.2    71.8    14.3    17.6    5.51 0       middle 
 9 04015    Mohav… AZ       10.2    46.7    21      19.6   18.7  1       highest
10 04017    Navaj… AZ       13.6    46.7    20.7    14.4   26.0  0       highest
# … with 305 more rows, 1 more variable: county_ranked <dbl>, and abbreviated
#   variable names ¹​diabetes_prevalence, ²​median_income, ³​adult_smoking,
#   ⁴​excessive_drinking, ⁵​limited_access_healthy_foods,
#   ⁶​excessive_drinking_cat, ⁷​limited_healthy_cat
Hmisc::describe(chr_2022)
chr_2022 

 11  Variables      315  Observations
--------------------------------------------------------------------------------
fipscode 
       n  missing distinct 
     315        0      315 

lowest : 04001 04003 04005 04007 04009, highest: 53069 53071 53073 53075 53077
--------------------------------------------------------------------------------
county 
       n  missing distinct 
     315        0      284 

lowest : Adams County   Allen County   Apache County  Appling County Ashland County
highest: Worth County   Wyandot County Yakima County  Yavapai County Yuma County   
--------------------------------------------------------------------------------
state 
       n  missing distinct 
     315        0        5 

lowest : AZ GA MA OH WA, highest: AZ GA MA OH WA
                                        
Value         AZ    GA    MA    OH    WA
Frequency     15   159    14    88    39
Proportion 0.048 0.505 0.044 0.279 0.124
--------------------------------------------------------------------------------
diabetes_prevalence 
       n  missing distinct     Info     Mean      Gmd      .05      .10 
     315        0       93        1    11.71    2.637     8.27     8.80 
     .25      .50      .75      .90      .95 
   10.10    11.30    13.40    14.86    15.76 

lowest :  6.9  7.1  7.2  7.3  7.4, highest: 17.4 17.6 18.3 18.5 18.7
--------------------------------------------------------------------------------
median_income 
       n  missing distinct     Info     Mean      Gmd      .05      .10 
     315        0      314        1    57.34    16.17    38.29    41.65 
     .25      .50      .75      .90      .95 
   46.43    54.28    65.13    76.60    84.72 

lowest :  28.004  35.215  35.225  35.937  35.997
highest: 104.519 106.348 111.158 114.423 116.690
--------------------------------------------------------------------------------
adult_smoking 
       n  missing distinct     Info     Mean      Gmd      .05      .10 
     315        0      142        1    21.52      4.7    14.27    15.04 
     .25      .50      .75      .90      .95 
   18.55    22.00    24.55    26.60    27.43 

lowest : 10.0 11.6 12.1 12.2 12.5, highest: 28.8 28.9 29.3 30.2 30.3
--------------------------------------------------------------------------------
excessive_drinking 
       n  missing distinct     Info     Mean      Gmd      .05      .10 
     315        0      315        1    18.02    2.209    14.99    15.53 
     .25      .50      .75      .90      .95 
   16.68    17.95    19.19    20.16    21.27 

lowest : 12.84939 13.07664 13.53404 13.64240 13.85782
highest: 23.80088 24.22215 24.87565 25.41218 25.97382
--------------------------------------------------------------------------------
limited_access_healthy_foods 
       n  missing distinct     Info     Mean      Gmd      .05      .10 
     310        5      310        1    8.209    6.965   0.2957   1.2185 
     .25      .50      .75      .90      .95 
  3.4036   6.7804  11.1510  15.5725  21.0486 

lowest :  0.00000000  0.00261523  0.00517053  0.00632370  0.03159322
highest: 28.04342013 29.72759446 35.34135905 39.34128842 47.43235975
--------------------------------------------------------------------------------
excessive_drinking_cat 
       n  missing distinct 
     315        0        2 
                      
Value          0     1
Frequency    165   150
Proportion 0.524 0.476
--------------------------------------------------------------------------------
limited_healthy_cat 
       n  missing distinct 
     310        5        5 

lowest : lowest  low     middle  high    highest
highest: lowest  low     middle  high    highest
                                                  
Value       lowest     low  middle    high highest
Frequency       62      62      62      62      62
Proportion     0.2     0.2     0.2     0.2     0.2
--------------------------------------------------------------------------------
county_ranked 
       n  missing distinct     Info     Mean      Gmd 
     315        0        1        0        1        0 
              
Value        1
Frequency  315
Proportion   1
--------------------------------------------------------------------------------
# see number of distinct values per column
chr_2022 |> summarize(across(diabetes_prevalence:limited_healthy_cat, ~n_distinct(.)))
# A tibble: 1 × 7
  diabetes_prevalence median_income adult_smok…¹ exces…² limit…³ exces…⁴ limit…⁵
                <int>         <int>        <int>   <int>   <int>   <int>   <int>
1                  93           314          142     315     311       2       6
# … with abbreviated variable names ¹​adult_smoking, ²​excessive_drinking,
#   ³​limited_access_healthy_foods, ⁴​excessive_drinking_cat,
#   ⁵​limited_healthy_cat
# see number of missing values for each state -> all above 75% completeness
chr_2022 |> filter(state == "AZ") |> miss_var_summary()
# A tibble: 11 × 3
   variable                     n_miss pct_miss
   <chr>                         <int>    <dbl>
 1 fipscode                          0        0
 2 county                            0        0
 3 state                             0        0
 4 diabetes_prevalence               0        0
 5 median_income                     0        0
 6 adult_smoking                     0        0
 7 excessive_drinking                0        0
 8 limited_access_healthy_foods      0        0
 9 excessive_drinking_cat            0        0
10 limited_healthy_cat               0        0
11 county_ranked                     0        0
chr_2022 |> filter(state == "GA") |> miss_var_summary()
# A tibble: 11 × 3
   variable                     n_miss pct_miss
   <chr>                         <int>    <dbl>
 1 limited_access_healthy_foods      4     2.52
 2 limited_healthy_cat               4     2.52
 3 fipscode                          0     0   
 4 county                            0     0   
 5 state                             0     0   
 6 diabetes_prevalence               0     0   
 7 median_income                     0     0   
 8 adult_smoking                     0     0   
 9 excessive_drinking                0     0   
10 excessive_drinking_cat            0     0   
11 county_ranked                     0     0   
chr_2022 |> filter(state == "OH") |> miss_var_summary()
# A tibble: 11 × 3
   variable                     n_miss pct_miss
   <chr>                         <int>    <dbl>
 1 fipscode                          0        0
 2 county                            0        0
 3 state                             0        0
 4 diabetes_prevalence               0        0
 5 median_income                     0        0
 6 adult_smoking                     0        0
 7 excessive_drinking                0        0
 8 limited_access_healthy_foods      0        0
 9 excessive_drinking_cat            0        0
10 limited_healthy_cat               0        0
11 county_ranked                     0        0
chr_2022 |> filter(state == "MA") |> miss_var_summary()
# A tibble: 11 × 3
   variable                     n_miss pct_miss
   <chr>                         <int>    <dbl>
 1 fipscode                          0        0
 2 county                            0        0
 3 state                             0        0
 4 diabetes_prevalence               0        0
 5 median_income                     0        0
 6 adult_smoking                     0        0
 7 excessive_drinking                0        0
 8 limited_access_healthy_foods      0        0
 9 excessive_drinking_cat            0        0
10 limited_healthy_cat               0        0
11 county_ranked                     0        0
chr_2022 |> filter(state == "WA") |> miss_var_summary()
# A tibble: 11 × 3
   variable                     n_miss pct_miss
   <chr>                         <int>    <dbl>
 1 limited_access_healthy_foods      1     2.56
 2 limited_healthy_cat               1     2.56
 3 fipscode                          0     0   
 4 county                            0     0   
 5 state                             0     0   
 6 diabetes_prevalence               0     0   
 7 median_income                     0     0   
 8 adult_smoking                     0     0   
 9 excessive_drinking                0     0   
10 excessive_drinking_cat            0     0   
11 county_ranked                     0     0   
# number of values per category -> see task 4, checking value distributions

# statistics on quantitative variables and original versions of binary and categorical 
mosaic::favstats(~diabetes_prevalence, data = chr_2022)
 min   Q1 median   Q3  max     mean       sd   n missing
 6.9 10.1   11.3 13.4 18.7 11.70889 2.338064 315       0
mosaic::favstats(~median_income, data = chr_2022)
    min      Q1 median      Q3    max     mean       sd   n missing
 28.004 46.4285 54.278 65.1275 116.69 57.33792 14.94116 315       0
mosaic::favstats(~adult_smoking, data = chr_2022)
 min    Q1 median    Q3  max     mean       sd   n missing
  10 18.55     22 24.55 30.3 21.51651 4.138246 315       0
mosaic::favstats(~excessive_drinking, data = chr_2022)
      min       Q1   median       Q3      max     mean       sd   n missing
 12.84939 16.67502 17.95007 19.19164 25.97382 18.02091 2.018204 315       0
mosaic::favstats(~limited_access_healthy_foods, data = chr_2022)
 min       Q1   median     Q3      max    mean      sd   n missing
   0 3.403644 6.780383 11.151 47.43236 8.20898 6.74796 310       5
# show value distributions for categorical variables
chr_2022 |> tabyl(state)
 state   n    percent
    AZ  15 0.04761905
    GA 159 0.50476190
    MA  14 0.04444444
    OH  88 0.27936508
    WA  39 0.12380952
chr_2022 |> tabyl(excessive_drinking_cat)
 excessive_drinking_cat   n   percent
                      0 165 0.5238095
                      1 150 0.4761905
chr_2022 |> tabyl(limited_healthy_cat)
 limited_healthy_cat  n    percent valid_percent
              lowest 62 0.19682540           0.2
                 low 62 0.19682540           0.2
              middle 62 0.19682540           0.2
                high 62 0.19682540           0.2
             highest 62 0.19682540           0.2
                <NA>  5 0.01587302            NA

3.2 Saving and Sharing

We will save the data as an R dataset into the same folder as the project proposal.

chr_2022
# A tibble: 315 × 11
   fipscode county state diabe…¹ media…² adult…³ exces…⁴ limit…⁵ exces…⁶ limit…⁷
   <chr>    <chr>  <fct>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl> <fct>   <fct>  
 1 04001    Apach… AZ       15.7    36.3    23.9    15.3   35.3  0       highest
 2 04003    Cochi… AZ       11.3    51.2    17.6    18.3   15.6  1       highest
 3 04005    Cocon… AZ        9.4    57.1    18.1    20.5   13.3  1       highest
 4 04007    Gila … AZ       11.2    49.3    19.8    21.5   11.0  1       high   
 5 04009    Graha… AZ       11.9    55.4    17.4    18.5   15.7  1       highest
 6 04011    Green… AZ       11.5    67.5    15.2    19.5   14.0  1       highest
 7 04012    La Pa… AZ       12.4    41.6    19.5    17.1   26.5  0       highest
 8 04013    Maric… AZ       10.2    71.8    14.3    17.6    5.51 0       middle 
 9 04015    Mohav… AZ       10.2    46.7    21      19.6   18.7  1       highest
10 04017    Navaj… AZ       13.6    46.7    20.7    14.4   26.0  0       highest
# … with 305 more rows, 1 more variable: county_ranked <dbl>, and abbreviated
#   variable names ¹​diabetes_prevalence, ²​median_income, ³​adult_smoking,
#   ⁴​excessive_drinking, ⁵​limited_access_healthy_foods,
#   ⁶​excessive_drinking_cat, ⁷​limited_healthy_cat
# save file as R dataset
saveRDS(chr_2022, file = "chr_2022_Max_Tjen.Rds")

4 Codebook

We also have to create codebooks for each state and variable. For the state codebook, information about each state’s name, abbreviation, and number of counties is provided. For the variable codebook, information about each variable’s name, description, original variable name, and number of missing values is provided.

# get amount of counties by state
chr_2022 |> count(state)
# A tibble: 5 × 2
  state     n
  <fct> <int>
1 AZ       15
2 GA      159
3 MA       14
4 OH       88
5 WA       39
# get amount of missing values by column
chr_2022 |> miss_var_summary()
# A tibble: 11 × 3
   variable                     n_miss pct_miss
   <chr>                         <int>    <dbl>
 1 limited_access_healthy_foods      5     1.59
 2 limited_healthy_cat               5     1.59
 3 fipscode                          0     0   
 4 county                            0     0   
 5 state                             0     0   
 6 diabetes_prevalence               0     0   
 7 median_income                     0     0   
 8 adult_smoking                     0     0   
 9 excessive_drinking                0     0   
10 excessive_drinking_cat            0     0   
11 county_ranked                     0     0   
# get median value cutoff of unemployment percentage 
summary(chr_2022["excessive_drinking"])
 excessive_drinking
 Min.   :12.85     
 1st Qu.:16.68     
 Median :17.95     
 Mean   :18.02     
 3rd Qu.:19.19     
 Max.   :25.97     

4.1 State Table

state abbreviation # of counties
Arizona AZ 15
Georgia GA 159
Massachusetts MA 14
Ohio OH 88
Washington WA 39
- - -
Total - 315

4.2 Variable Table

Variable Description Original Variable # Missing Values
fipscode 5-digit FIPS code fipscode 0
county name county 0
state state abbreviation state 0
county_ranked county ranked (yes = 1, no = 0) county_ranked 0
diabetes_prevalence [outcome] diabetes prevalence percentage v060_rawvalue 0
median_income [quantitative] median household income in thousands v063_rawvalue 0
adult_smoking [quantitative] adult smoking percentage v009_rawvalue 0
excessive_drinking excessive drinking percentage v049_rawvalue 0
limited_access_healthy_foods limited access to healthy foods percentage v083_rawvalue 5
excessive_drinking_cat [categorical] 2 categories: 0 if value < 18.02, 1 if otherwise (see task 4 for how values to split variable was chosen) v049_rawvalue 0
limited_healthy_cat [categorical] 5 categories: ‘lowest’ if value <2.76, ‘low’ if 2.76 <= value < 5.51, ‘middle’ if 5.51 <= value < 8.39, ‘high’ if 8.39 <= value < 12.51, ‘highest’ if 12.51 <= value <= 47.43 (see task 4 for how values to split variable was chosen) v083_rawvalue 5

5 Biggest Challenge

The most challenging part of the project so far for me was to convert the limited access to healthy foods variable into a multi-categorical variable. The process wasn’t too hard, more so just the best way to do it. For example, in the beginning, I wanted to use specified values to be cutoffs. However, because of the requirement of having at least 10 counties in each category, this wasn’t possible because of the range of data and the distribution. There were a couple of other methods I flirted with, but each of them had some sort of downfall that led to them being tossed out. At the end of the day, I went with a simple even cut, where the cut2 function divided each category evenly so that each one consists of the same amount of counties (+-1).

6 Analysis 1

6.1 Variables

We will be using median_income as the quantitative predictor variable and diabetes_prevalence as the outcome variable. The median_income variable measures the median household income in thousands of dollars of residents in the county and the diabetes_prevalence variable measures the diabetes prevalence percentage of residents in the county. From our tibble (chr_2022), the variables are listed as median_income (predictor) and diabetes_prevalence (outcome) across the states of Arizona, Georgia, Massachusetts, Ohio, and Washington, and each variable has 315 counties with complete data. For Cuyahoga County, Ohio, the values of the predictor and outcome variable are median_income = 55.128 and diabetes_prevalence = 11.1.

# only get median_income and diabetes_prevalence
a1_data <- chr_2022 |> 
  select(median_income, diabetes_prevalence) |> 
  filter(complete.cases(median_income, diabetes_prevalence))

dim(a1_data)
[1] 315   2
# get values for Cuyahoga County
chr_2022 |> filter(state == "OH") |>
  filter(county == "Cuyahoga County") |>
  select(median_income, diabetes_prevalence)
# A tibble: 1 × 2
  median_income diabetes_prevalence
          <dbl>               <dbl>
1          55.1                11.1

6.2 Research Question

How well does a county’s median income predict their diabetes prevalence in 315 counties across the states of Arizona, Georgia, Massachusetts, Ohio, and Washington?

6.3 Data Visualization

ggplot(a1_data, aes(x = median_income, y = diabetes_prevalence)) +
  geom_point(col = "black") + 
  geom_smooth(method = "lm", col = "red", se = FALSE) + 
  geom_smooth(method = "loess", col = "blue", se = FALSE) + 
  labs(title = "Relationship Between Median Income and Diabetes Prevalence",
       x = "Median Income of County in Thousands of Dollars",
       y = "Diabetes Prevalence Percentage of County")

From this plot, it appears that there is a negative correlation between counties’ median income and diabetes prevalence. While the variable relationship looks pretty linear, there appears to be a curve, which indicates that there is some skew in the data. This may mean that a transformation may be needed before running a linear model on the data.

6.4 Transformation Assessment

When looking at transformations, we looked at using a logarithm, an inverse, or a square transformation on the outcome variable (diabetes prevalence). To evaluate each of them, a QQ plot was used and compared with the other transformations, including a QQ plot of the untransformed data. From these plots, it appeared that a logarithm transformation appears to work best with this subset of data, as the data followed the QQ line the best. Although the data is still skewed and a slight curve still exists, the data isn’t as skewed as before.

ggplot(a1_data, aes(x = median_income, y = log(diabetes_prevalence))) +
  geom_point(col = "black") + 
  geom_smooth(method = "lm", col = "red", se = FALSE) + 
  geom_smooth(method = "loess", col = "blue", se = FALSE) + 
  labs(title = "Relationship Between Median Income and Diabetes Prevalence",
       x = "Median Income of County in Thousands of Dollars",
       y = "log(Diabetes Prevalence Percentage of County)")

6.5 Fitted Model

a1_model <- lm(log(diabetes_prevalence) ~ median_income, data = a1_data)

# R^2, number of observations
glance(a1_model) |> select(r.squared, sigma, nobs)
# A tibble: 1 × 3
  r.squared sigma  nobs
      <dbl> <dbl> <int>
1     0.585 0.128   315
# pearson correlation
cor(a1_data$median_income, a1_data$diabetes_prevalence)
[1] -0.7458889

6.5.1 Prediction Equation

# coefficients
extract_eq(a1_model, use_coefs = TRUE, operator_location = "start",
           wrap = TRUE, coef_digits = 2)

\[ \begin{aligned} \operatorname{\widehat{log(diabetes\_prevalence)}} &= 3.02 - 0.01(\operatorname{median\_income}) \end{aligned} \]

The prediction equation is log(diabetes_prevalence) = 3.02 - 0.01(median_income). This means that if a county has a median income of 0,000 dollars, then the expected log value of the county’s diabetes prevalence percentage is 3.02. It also means that for each increase of 1,000 dollars of a county’s median income, the expected log value of the county’s diabetes prevalence percentage will decrease by 0.01.

6.5.2 Model Coefficients

tidy(a1_model, conf.int = TRUE, conf.level = 0.90) |> 
  select(term, estimate, conf.low, conf.high) |>
  kbl(digits = 2)
term estimate conf.low conf.high
(Intercept) 3.02 2.98 3.07
median_income -0.01 -0.01 -0.01

6.5.3 Summaries of Model Fit

\(R^2\) Residual Standard Error Number of Fitted Observations Pearson Correlation
0.585 0.128 315 -0.746

6.6 Residual Analysis

6.6.1 Residual Plots

a1_aug <- augment(a1_model, newdata = a1_data)

p1 <- ggplot(a1_aug, aes(x = .fitted, y = .resid)) +
  geom_point() +
  geom_smooth(method = "lm", col = "red", se = FALSE) + 
  geom_smooth(method = "loess", col = "blue", se = FALSE) +
  labs(title = "Residuals vs. Fitted Values", 
       x = "Fitted log(diabetes_prevalence) Values", y = "Residuals")

p2 <- ggplot(a1_aug, aes(sample = .resid)) +
  geom_qq(col = "black") + 
  geom_qq_line(col = "red") + 
  labs(title = "Normal Q-Q: Model Residuals")

p1 / p2

From the first plot, it appears that there may be some non-linearity in the regression relationship as there is a curve in the residuals v. fitted values plot. This means that the model fits some points better than others, as there isn’t a relative constant residual value. The variance across the board is also pretty constant, with the left side looking a bit unbalanced relative to the right side likely because of its point scarcity. From the second plot, it appears that the residuals are pretty normally distributed and has a couple of outliers on each end of the value extremes.

6.6.2 Cuyahoga County Comparison

# get income and diabetes values
cuyahoga <- chr_2022 |> filter(state == "OH") |>
  filter(county == "Cuyahoga County") |>
  select(median_income, diabetes_prevalence)

# predict with model
cuyahoga_prediction <- augment(a1_model, newdata = cuyahoga)
# get untransformed value -> un-log()
fitted_diabetes <- exp(cuyahoga_prediction$.fitted)

glue("Cuyahoga Actual: {cuyahoga$diabetes_prevalence}%
Cuyahoga Predicted: {round(fitted_diabetes, 2)}%")
Cuyahoga Actual: 11.1%
Cuyahoga Predicted: 11.74%

6.6.3 Largest Residual Counties

# get predicted values for all counties
plot(a1_model, which = c(1:2))

# print counties in order of residual magnitude
indices <- c(180, 73, 175)
for (index in indices) {
  # original data
  print(chr_2022[index, ] |> select(county, state, median_income, diabetes_prevalence))
  # residual value
  print(a1_aug[index, ] |> select(median_income, diabetes_prevalence, .fitted, .resid))
}
# A tibble: 1 × 4
  county          state median_income diabetes_prevalence
  <chr>           <fct>         <dbl>               <dbl>
1 Franklin County MA             62.9                 7.6
# A tibble: 1 × 4
  median_income diabetes_prevalence .fitted .resid
          <dbl>               <dbl>   <dbl>  <dbl>
1          62.9                 7.6    2.38 -0.356
# A tibble: 1 × 4
  county         state median_income diabetes_prevalence
  <chr>          <fct>         <dbl>               <dbl>
1 Forsyth County GA             117.                 8.6
# A tibble: 1 × 4
  median_income diabetes_prevalence .fitted .resid
          <dbl>               <dbl>   <dbl>  <dbl>
1          117.                 8.6    1.84  0.316
# A tibble: 1 × 4
  county            state median_income diabetes_prevalence
  <chr>             <fct>         <dbl>               <dbl>
1 Barnstable County MA             76.3                 6.9
# A tibble: 1 × 4
  median_income diabetes_prevalence .fitted .resid
          <dbl>               <dbl>   <dbl>  <dbl>
1          76.3                 6.9    2.25 -0.316

The county with the largest absolute value residual is Franklin County, MA (-0.356). For the second largest absolute value residual, there are two counties that are tied: Forsyth County, GA (0.316) and Barnstable County, MA (-0.316).

6.7 Conclusions and Limitations

This analysis section investigated the relationship between counties’ median household income and their diabetes prevalence percentage. Based on the analysis performed, it appears as if there is a decently negative relationship between the two variables. This can be most clearly seen by the pearson correlation score of -0.746. The residual standard error values also points to the model being pretty reliable in predicting county diabetes prevalence percentages. When converting the residual standard error of 0.128 back to the original range (\(e^{0.128}\)), the value is 1.137. This indicates the standard deviation of residuals, so a low score of 1.137 means that the fitted values tend to be pretty close to the actual ones. While these demonstrate a relatively strong correlation, the model’s \(R^2\) score of 0.585 shows that median household income may not be a very good predictor of diabetes prevalence variability.

Based on the data analysis, there does appear to be some limitations to our conclusions from analysis 1. The first linear model assumption of a linear relationship may not be fully met by our data, even once it’s transformed. When looking at the residuals versus fitted values plot, a slight curve can be seen. This means that the relationship between median income and log(diabetes prevalence) may not be fully linear, so a linear model may not be the best way to use median income to predict diabetes prevalence. Some of this may be attributed to outlier values though, which can be seen on the normal QQ plot of residuals. Most of the values stay along the normal line, although at each of the ends, there are some outliers. While there aren’t that many, the outliers may skew the model results a bit in one way or another. These outliers may also be due to our data’s selection of states, regarding median household income. Regarding median income, Massachusetts and Washington are both among the top 7 states and are pretty well above the US median income while Ohio and Georgia are in the bottom 15 states and noticably lower than the US median. This means that this subset of states may not be best suited to accurately represent the US when relating median household income to diabetes prevalence percentage.

7 Analysis 2

7.1 Variables

For analysis 2, we will be using the limited access to healthy food categorical variable (limited_healthy_cat) as the predictor with a baseline category of ‘lowest’ and diabetes prevalence (diabetes_prevalence) as the outcome variable from the chr_2022 tibble. limited_healthy_cat represents a category that corresponds to a county’s percentage of limited access to healthy foods, so in essence the percentage of residents that can’t easily obtain healthy foods. Within the variable, there are five categories, which were divided using a method that made sure each category had an equal number of counties (+- 1). The diabetes_prevalence variable measures the diabetes prevalence percentage of residents in the county. The counties in the data come from Arizona, Georgia, Massachusetts, Ohio, and Washington and there are 5 counties with missing data for the predictor variable. With this, we are going to drop these counties as make a very small percentage (1.59%) of the entire dataset and they were also excluded when splitting limited_healthy_cat into various categories For Cuyahoga County, Ohio, the values of the predictor and outcome variable are limited_healthy_cat = ‘low’ and diabetes_prevalence = 11.1.

# only get limited_healthy_cat and diabetes_prevalence
a2_data <- chr_2022 |> 
  select(limited_healthy_cat, diabetes_prevalence) |> 
  filter(complete.cases(limited_healthy_cat, diabetes_prevalence))

dim(a2_data)
[1] 310   2
# get values for Cuyahoga County
chr_2022 |> filter(state == "OH") |>
  filter(county == "Cuyahoga County") |>
  select(limited_healthy_cat, diabetes_prevalence)
# A tibble: 1 × 2
  limited_healthy_cat diabetes_prevalence
  <fct>                             <dbl>
1 low                                11.1

7.2 Research Question

Are there statistical significant differences in mean values of diabetes prevalence for each progressive level of limited access to healthy foods (lowest-low, low-middle, middle-high, high-highest) in 310 counties across the states of Arizona, Georgia, Massachusetts, Ohio, and Washington?

7.3 Data Visualization

ggplot(a2_data, aes(x = limited_healthy_cat, y = diabetes_prevalence)) +
  geom_violin(aes(fill = limited_healthy_cat)) + 
  geom_boxplot(width = 0.25) + 
  coord_flip() + 
  labs(title = "Diabetes Prevalence by Limited Access to Healthy Foods Level",
       x = "Limited Access to Healthy Foods Level",
       y = "Diabetes Prevalence")

mosaic::favstats(diabetes_prevalence ~ limited_healthy_cat, data = a2_data)
  limited_healthy_cat min     Q1 median     Q3  max     mean       sd  n
1              lowest 7.1 10.325  12.05 13.900 18.5 12.28871 2.469958 62
2                 low 7.3  8.825  10.30 12.075 16.4 10.75806 2.312939 62
3              middle 8.0  9.800  10.65 11.975 18.3 11.08226 2.059725 62
4                high 6.9 10.150  11.45 12.575 18.7 11.44032 1.943839 62
5             highest 8.4 11.550  13.10 14.500 18.3 13.08871 2.136728 62
  missing
1       0
2       0
3       0
4       0
5       0

For analysis 2, we will not be transforming the outcome variable as the outcome variable is pretty normally distributed with the exception of a few outliers. Furthermore, the categorical predictor variable has very similar variance across all category levels. From the boxplot with violin plots, it appears that all of the predictor variable levels have a similar range of values. It can also be seen that the levels are all relatively normally distributed, albeit with various levels of peak values. None of the levels appear to be near identical, in any sense, but one interesting thing to look at is the median values of each category level. Excluding the ‘lowest’ level, the median value of diabetes prevalence of each level increases within each level, which may indicate that with higher levels of limited access to healthy foods, there are higher levels of diabetes prevalence.

7.4 Fitted Model

a2_model <- lm(diabetes_prevalence ~ limited_healthy_cat, data = a2_data)

7.4.1 Prediction Equation

# coefficients
extract_eq(a2_model, use_coefs = TRUE, operator_location = "start",
           wrap = TRUE, coef_digits = 2, terms_per_line = 1)

\[ \begin{aligned} \operatorname{\widehat{diabetes\_prevalence}} &= 12.29\\ &\quad - 1.53(\operatorname{limited\_healthy\_cat}_{\operatorname{low}})\\ &\quad - 1.21(\operatorname{limited\_healthy\_cat}_{\operatorname{middle}})\\ &\quad - 0.85(\operatorname{limited\_healthy\_cat}_{\operatorname{high}})\\ &\quad + 0.8(\operatorname{limited\_healthy\_cat}_{\operatorname{highest}}) \end{aligned} \]

The prediction equation is diabetes_prevalence = 12.29 - 1.53(limited_healthy_cat\(_{low}\)) - 1.21(limited_healthy_cat\(_{middle}\)) - 0.85(limited_healthy_cat\(_{high}\)) + 0.80(limited_healthy_cat\(_{highest}\)). This means that a county’s predicted diabetes prevalence is dependent on their limited access to healthy foods categorical level. If their level is lowest, then the expected diabetes prevalence is 12.29. Since each county can only be in one category level, then at most only one of the coefficients will be used. If their level is lowest, then it’s expected that their diabetes prevalence will be the intercept value (12.29). If their level is low, then it’s expected that their diabetes prevalence will decrease by 1.53 to 10.76. If their level is middle, then it’s expected that their diabetes prevalence will decrease by 1.21 to 11.08. If their level is high, then it’s expected that their diabetes prevalence will decrease by 0.85 to 11.44. If their level is highest, then it’s expected that their diabetes prevalence will increase by 0.80 to 13.09.

7.4.2 Model Coefficients

tidy(a2_model, conf.int = TRUE, conf.level = 0.90) |> 
  select(term, estimate, conf.low, conf.high) |>
  kbl(digits = 2)
term estimate conf.low conf.high
(Intercept) 12.29 11.83 12.75
limited_healthy_catlow -1.53 -2.18 -0.88
limited_healthy_catmiddle -1.21 -1.86 -0.56
limited_healthy_cathigh -0.85 -1.50 -0.20
limited_healthy_cathighest 0.80 0.15 1.45

7.4.3 Summaries of Model Fit

tidy(anova(a2_model)) |> kbl(digits = 3) |> kable_classic_2()
term df sumsq meansq statistic p.value
limited_healthy_cat 4 223.595 55.899 11.628 0
Residuals 305 1466.255 4.807 NA NA
glance(a2_model) |> select(r.squared, sigma, nobs)
# A tibble: 1 × 3
  r.squared sigma  nobs
      <dbl> <dbl> <int>
1     0.132  2.19   310
\(R^2\) Residual Standard Error Number of Fitted Observations
0.132 2.19 310

From the Anova table, we can see that we can reject the null hypothesis since the p-value is smaller than 0.10 (can’t see because of digits but value is 8.433e-09). This means that at least one of the mean values of the category groups is statistically different than the others. Since we can conclude that a county’s level of limited access to healthy foods provides meaningful predictive value as to the means’ of each group, we will perform Tukey’s Honestly Significant Differences test to see if there are statistically differences between the mean’s of each group versus all the other groups.

TukeyHSD(aov(lm(diabetes_prevalence ~ limited_healthy_cat, data = a2_data)), 
         conf.level = 0.90, ordered = FALSE)
  Tukey multiple comparisons of means
    90% family-wise confidence level

Fit: aov(formula = lm(diabetes_prevalence ~ limited_healthy_cat, data = a2_data))

$limited_healthy_cat
                     diff        lwr        upr     p adj
low-lowest     -1.5306452 -2.5037267 -0.5575637 0.0011708
middle-lowest  -1.2064516 -2.1795331 -0.2333701 0.0200116
high-lowest    -0.8483871 -1.8214686  0.1246944 0.2001383
highest-lowest  0.8000000 -0.1730815  1.7730815 0.2534513
middle-low      0.3241935 -0.6488880  1.2972750 0.9233269
high-low        0.6822581 -0.2908234  1.6553396 0.4155597
highest-low     2.3306452  1.3575637  3.3037267 0.0000001
high-middle     0.3580645 -0.6150170  1.3311460 0.8932290
highest-middle  2.0064516  1.0333701  2.9795331 0.0000061
highest-high    1.6483871  0.6753056  2.6214686 0.0003569

By running Tukey’s Honestly Significant Differences test, we can determine which specific groups of limited access to healthy foods have statistically different means. Using a 90% confidence interval again (\(\alpha\) = 0.10), we can see that 5 pairs of groups have statistically different diabetes prevalence mean’s. Those groups would be low-lowest (0.001), middle-lowest (0.020), highest-low (0.000), highest-middle (0.000), and highest-high (0.000).

7.5 Prediction Analysis

7.5.1 Residual Plot

a2_aug <- augment(a2_model, newdata = a2_data)

p1 <- ggplot(a2_aug, aes(x = .fitted, y = .resid, color = limited_healthy_cat)) +
  geom_point() + 
  geom_smooth(method = "lm", col = "red", se = FALSE) + 
  geom_smooth(method = "loess", col = "blue", se = FALSE) + 
  labs(title = "Residuals vs. Fitted Values", 
       x = "Fitted diabetes_prevalence Values", y = "Residual Values")

p2 <- ggplot(a2_aug, aes(sample = .resid)) +
  geom_qq() + 
  geom_qq_line(col = "red") + 
  labs(title = "Residual QQ Plot",
       y = "")

p3 <- ggplot(a2_aug, aes(x = .resid, y = "")) +
  geom_violin(fill = "dodger blue") +
  geom_boxplot(width = 0.25) + 
  labs(title = "Residual Value Histogram",
       y = "", 
       x = "")

# didn't patch them together as plots didn't look good squeezed in any way
p1

p2

p3

From the first two plots, it appears that the regression relationship between level of limited access to healthy foods and diabetes prevalence fits pretty well. The first plot makes it look linear as the line of best fit has no curve. In general, all category levels seem to have relatively similar variance when not considering outliers, which can be seen when looking at each group individually in plot 2. The regression residuals look pretty normal in the QQ plot as most points are along the normal QQ line. However, it appears to have a slight upward curve, which indicates a right skew. This is reinforced in the third plot, as the median is slightly shifted left and there is a slightly longer right tail.

7.5.2 Prediction for Cuyahoga County, OH

# get limited access to healthy foods category and diabetes value
cuyahoga <- chr_2022 |> filter(state == "OH") |>
  filter(county == "Cuyahoga County") |>
  select(limited_healthy_cat, diabetes_prevalence)

# predict with model
cuyahoga_prediction <- augment(a2_model, newdata = cuyahoga)
fitted_diabetes <- cuyahoga_prediction$.fitted

glue("Cuyahoga Actual: {cuyahoga$diabetes_prevalence}%
Cuyahoga Predicted: {round(fitted_diabetes, 2)}%")
Cuyahoga Actual: 11.1%
Cuyahoga Predicted: 10.76%

7.5.3 Two Least Successfully Fit Counties

# get predicted values for all counties
plot(a2_model, which = c(1:2))

# print counties in order of residual magnitude
indices <- c(140, 34)
for (index in indices) {
  # original data
  completes <- chr_2022 |> filter(complete.cases(chr_2022))
  print(completes[index, ] |> select(county, state, limited_healthy_cat, diabetes_prevalence))
  # residual value
  print(a2_aug[index, ] |> select(limited_healthy_cat, diabetes_prevalence, .fitted, .resid))
}
# A tibble: 1 × 4
  county         state limited_healthy_cat diabetes_prevalence
  <chr>          <fct> <fct>                             <dbl>
1 Stewart County GA    high                               18.7
# A tibble: 1 × 4
  limited_healthy_cat diabetes_prevalence .fitted .resid
  <fct>                             <dbl>   <dbl>  <dbl>
1 high                               18.7    11.4   7.26
# A tibble: 1 × 4
  county         state limited_healthy_cat diabetes_prevalence
  <chr>          <fct> <fct>                             <dbl>
1 Calhoun County GA    middle                             18.3
# A tibble: 1 × 4
  limited_healthy_cat diabetes_prevalence .fitted .resid
  <fct>                             <dbl>   <dbl>  <dbl>
1 middle                             18.3    11.1   7.22

The county with the largest absolute value residual is Stewart County, GA (7.260) and the county with the second largest absolute value residual is Calhoun County, GA (7.218).

7.6 Conclusions and Limitations

In the second analysis, we wanted to see if there were statistical differences in mean values of diabetes prevalence for each progressive level of limited access to healthy foods. After running an ANOVA test and then Tukey’s honestly significant difference test, it was found that not all of the progressive groups had statistically different means. There were five pairs that were statistically significant, which were low-lowest, middle-lowest, highest-low, highest-middle, and highest-high. With that, the only progressive groups were lowest-low and high-highest. Something interesting to note is that each of the statistically significant pairs included either the lowest or highest limited access to healthy foods group. This may indicate that those were the only two that were very different than the other three (low, middle, high).

From our analysis, it doesn’t appear that there are very many limitations to our conclusions, so our conclusions are likely pretty solid. One thing to note is that for the middle and high groups of limited access to healthy foods, there are a couple of relatively extreme outliers. Something that may be an issue is that there was a right skew in the residuals, telling that there are more negative residual values than positive ones. The distribution is still normal though with a couple of outliers, which is a good sign when running a linear model. Another limitation is with the method used to divide counties up into various limited access to healthy foods levels. To ensure that each level had enough counties, we used a method that simply made it so each level had the same amount of counties. Because of that, the ranges of each level is not the same and some are much larger than others, so the levels are more represenative and relative to this data’s subset of US counties than the population as a whole.

8 Analysis 3

8.1 Variables

We will be using median income and state as predictor variables and diabetes prevalence as the outcome variable. The median income variable measures the county’s residents’ median household income in thousands of dollars, the state variable explains what state the county is in, and the diabetes prevalence variable measures the diabetes prevalence percentage of residents in the county. From our tibble (chr_2022), the variables are listed as median_income (predictor), state (predictor), and diabetes_prevalence (outcome) across the states of Arizona, Georgia, Massachusetts, Ohio, and Washington, and each variable has 315 counties with complete data. The state variable is considered an interaction term, as the intercept and slope of the equation will be impacted by the county’s state. For Cuyahoga County, Ohio, the values of the predictor and outcome variables are state = “OH”, median_income = 55.128, and diabetes_prevalence = 11.1.

# get state, median_income, and diabetes_prevalence
a3_data <- chr_2022 |> 
  select(state, median_income, diabetes_prevalence) |> 
  filter(complete.cases(median_income, diabetes_prevalence))

dim(a3_data)
[1] 315   3
# get values for Cuyahoga County
chr_2022 |> filter(state == "OH") |>
  filter(county == "Cuyahoga County") |>
  select(state, median_income, diabetes_prevalence)
# A tibble: 1 × 3
  state median_income diabetes_prevalence
  <fct>         <dbl>               <dbl>
1 OH             55.1                11.1

8.2 Research Question

Does a county’s state help make their median income a better predictor (better than model 1) of the county’s diabetes prevalence in 315 counties across the states of Arizona, Georgia, Massachusetts, Ohio, and Washington?

8.3 Data Visualization

ggplot(a3_data, aes(x = median_income, y = diabetes_prevalence)) +
  geom_point(col = "black") + 
  geom_smooth(method = "lm", col = "red", se = FALSE) + 
  geom_smooth(method = "loess", col = "blue", se = FALSE) + 
  facet_grid(state ~ ., labeller = "label_both") +
  guides(fill = "none") + 
  labs(title = "Relationship Between Median Income and Diabetes Prevalence by State",
       x = "Median Income of County in Thousands of Dollars",
       y = "Diabetes Prevalence Percentage of County")

From this plot, it appears that each individual state’s relationship between median income and diabetes prevalence is negative. The slope’s negative degree varies by state, along with the amount of data points. Georgia and Ohio have the most amount of counties, which means that they have many more data points than states like Arizona and Massachusetts. With that, Georgia and Ohio also have a larger range of values for both median income and diabetes prevalence. It can also be seen that Massachusetts has a higher range of median income while Arizona is on the lower range.

8.4 Fitted Model

# make Ohio baseline
a3_data <- a3_data |> mutate(state = fct_relevel(state, "OH"))

# create model
a3_model <- lm(diabetes_prevalence ~ median_income * state, data = a3_data)

# R^2, number of observations
glance(a3_model) |> select(r.squared, sigma, nobs)
# A tibble: 1 × 3
  r.squared sigma  nobs
      <dbl> <dbl> <int>
1     0.740  1.21   315

8.4.1 Prediction Equation

extract_eq(a3_model, use_coefs = TRUE, operator_location = "start",
           wrap = TRUE, coef_digits = 2,  terms_per_line = 1)

\[ \begin{aligned} \operatorname{\widehat{diabetes\_prevalence}} &= 14.58\\ &\quad - 0.06(\operatorname{median\_income})\\ &\quad + 3.68(\operatorname{state}_{\operatorname{AZ}})\\ &\quad + 4.45(\operatorname{state}_{\operatorname{GA}})\\ &\quad - 4.73(\operatorname{state}_{\operatorname{MA}})\\ &\quad - 1.69(\operatorname{state}_{\operatorname{WA}})\\ &\quad - 0.06(\operatorname{median\_income} \times \operatorname{state}_{\operatorname{AZ}})\\ &\quad - 0.05(\operatorname{median\_income} \times \operatorname{state}_{\operatorname{GA}})\\ &\quad + 0.04(\operatorname{median\_income} \times \operatorname{state}_{\operatorname{MA}})\\ &\quad + 0.01(\operatorname{median\_income} \times \operatorname{state}_{\operatorname{WA}}) \end{aligned} \]

The prediction equation from the model is diabetes_prevalence = 14.58 - 0.06(median_income) + 3.68(state\(_{AZ}\)) + 4.45(state\(_{GA}\)) - 4.73(state\(_{MA}\)) - 1.69(state\(_{WA}\)) - 0.06(median_income * state\(_{AZ}\)) - 0.05(median_income * state\(_{GA}\)) + 0.04(median_income * state\(_{MA}\)) + 0.01(median_income * state\(_{WA}\)). Because there is an interaction term, the slope used to get the fitted diabetes prevalence value is dependent on both the county’s state and median income. This means the fitted diabetes prevalence of a county in Ohio is 14.58 - 0.06(median income). There isn’t an interaction term (median income * state) because Ohio has been set as the baseline state for the model. For Arizona, the predicted prevalence is 14.58 - 0.06(median_income) + 3.68(state\(_{AZ}\)). For Georgia, the predicted prevalence is 14.58 - 0.06(median_income) + 4.45(state\(_{GA}\)). For Massachusetts, the predicted prevalence is 14.58 - 0.06(median_income) + 4.73(state\(_{MA}\)). For Washington, the predicted prevalence is 14.58 - 0.06(median_income) + 0.01(median_income * state\(_{WA}\)).

8.4.2 Model Coefficients

tidy(a3_model, conf.int = TRUE, conf.level = 0.90) |> 
  select(term, estimate, conf.low, conf.high) |>
  kbl(digits = 2)
term estimate conf.low conf.high
(Intercept) 14.58 13.49 15.68
median_income -0.06 -0.08 -0.05
stateAZ 3.68 0.57 6.78
stateGA 4.45 3.20 5.69
stateMA -4.73 -7.95 -1.51
stateWA -1.69 -3.74 0.37
median_income:stateAZ -0.06 -0.12 0.00
median_income:stateGA -0.05 -0.07 -0.03
median_income:stateMA 0.04 0.00 0.08
median_income:stateWA 0.01 -0.02 0.04

8.4.3 Summaries of Model Fit

\(R^2\) Residual Standard Error Number of Fitted Observations
0.740 1.21 315

8.5 Residual Analysis

8.5.1 Residual Plots

a3_aug <- augment(a3_model, newdata = a3_data)

p1 <- ggplot(a3_aug, aes(x = .fitted, y = .resid)) +
  geom_point() +
  geom_smooth(method = "lm", col = "red", se = FALSE) + 
  geom_smooth(method = "loess", col = "blue", se = FALSE) +
  labs(title = "Residuals vs. Fitted Values", 
       x = "Fitted diabetes_prevalence Values", y = "Residuals")

p2 <- ggplot(a3_aug, aes(sample = .resid)) +
  geom_qq(col = "black") + 
  geom_qq_line(col = "red") + 
  labs(title = "Normal Q-Q: Model Residuals")

p1 / p2

Overall, it looks like the predicted diabetes prevalence values for outlier counties have actually become more extreme and farther away from the actual values relative to analysis 1. Although the loess smooth curve looks less extreme than in analysis 1, it actually is the same if not more curved and it just appears less because the y-axis range is larger. For the majority of counties though, it appears that the analysis 3 model fits much better. This is evident through the first plot, where you can see a lot more of the points are closer to the line of best fit, which means that the fitted values are very close to the actual ones. It can also be seen in the QQ plot, where lots of the points in the middle are pretty much on the normal QQ line. While it looks like overall, the model has become more accurate by accounting for the county’s state, the residual variance appears to have increased. This can be seen in the first plot as the variance increases as the fitted value increases. Similarly in the second plot, the outliers on the tails are farther away from the QQ line which means that the outlier residual values are larger.

8.5.2 Cuyahoga County Comparison

# get income and diabetes values
cuyahoga <- chr_2022 |> filter(state == "OH") |>
  filter(county == "Cuyahoga County") |>
  select(state, median_income, diabetes_prevalence)

# predict with model
cuyahoga_prediction <- augment(a3_model, newdata = cuyahoga)
fitted_diabetes <- cuyahoga_prediction$.fitted

glue("Cuyahoga Actual: {cuyahoga$diabetes_prevalence}%
Cuyahoga Predicted: {round(fitted_diabetes, 2)}%")
Cuyahoga Actual: 11.1%
Cuyahoga Predicted: 11.03%

8.5.3 Largest Residual Counties

# get predicted values for all counties
plot(a3_model, which = c(1:2))

# print counties in order of residual magnitude
indices <- c(277, 143)
for (index in indices) {
  # original data
  print(chr_2022[index, ] |> select(county, state, median_income, diabetes_prevalence))
  # residual value
  print(a3_aug[index, ] |> select(median_income, diabetes_prevalence, .fitted, .resid))
}
# A tibble: 1 × 4
  county       state median_income diabetes_prevalence
  <chr>        <fct>         <dbl>               <dbl>
1 Adams County WA             56.4                14.7
# A tibble: 1 × 4
  median_income diabetes_prevalence .fitted .resid
          <dbl>               <dbl>   <dbl>  <dbl>
1          56.4                14.7    9.99   4.71
# A tibble: 1 × 4
  county         state median_income diabetes_prevalence
  <chr>          <fct>         <dbl>               <dbl>
1 Stewart County GA             40.2                18.7
# A tibble: 1 × 4
  median_income diabetes_prevalence .fitted .resid
          <dbl>               <dbl>   <dbl>  <dbl>
1          40.2                18.7    14.5   4.21

The county with the largest absolute value residual is Adams County, WA (4.71) and the county with the second largest absolute value residual is Stewart County, GA (4.21).

8.6 Conclusions and Limitations

In analysis 3, we wanted to investigate if a county’s state interacting with their median income helped become a better predictor of their diabetes prevalence. Based on our first analysis model using only median income to predict diabetes prevalence, the \(R^2\) value was 0.585 and residual standard error was 0.128. In this model with also including the county’s state, the \(R^2\) value is 0.740 and residual standard error is 1.210. \(R^2\) represents the proportion of the diabetes prevalence variance explained by regression model variables. With that, a higher value is better, as it means the relationship in the model between predictor and outcome variables is stronger. Given that the \(R^2\) value of this model is 0.155 higher and the residual standard error is 0.007 lower, we can determine that adding state as an interaction term with median income helps to predict a county’s diabetes prevalence more accurately. To further this idea, we will take a random sample of 50 indices of the data and see which model (1 or 3) performed better in terms of absolute residual value.

# set seed for reproducable results
set.seed(12345)

# create empty results table
results <- data.frame(matrix(ncol = 4, nrow = 0))
colnames(results) <- c('Actual', 'M1 Fitted', 'M3 Fitted', 'Better Fitted')

# create random index values
indices <- sample(1:315, 50, replace = FALSE)

# get absolute residual values for the indices
for (index in indices) {
  actual_value <- chr_2022[index, ]$diabetes_prevalence
  model1_resid <- abs(exp(a1_aug[index, ]$.resid))          # untransform residual
  model3_resid <- abs(a3_aug[index, ]$.resid)
  
  which_better <- 1
  if (model1_resid > model3_resid) {
    which_better <- 3
  }
  
  new_row <- c(actual_value, model1_resid, model3_resid, which_better)
  results[nrow(results) + 1,] <- new_row
}

head(results, 10)
   Actual M1 Fitted   M3 Fitted Better Fitted
1    11.0 0.8590740 2.765468752             1
2     9.8 1.1605060 0.651593041             3
3    10.6 0.9663765 0.001054092             3
4    11.7 0.9061598 0.067397747             3
5    10.0 0.9084960 0.623156854             3
6    13.7 1.0533586 0.238680600             3
7    10.5 1.0507130 0.515999020             3
8    11.0 1.1068639 0.045466894             3
9     8.7 0.9994500 0.438663165             3
10   11.3 0.9349680 0.085417045             3
# see breakdown of which model predicted a closer diabetes prevalence value
tabyl(results$`Better Fitted`)
 results$`Better Fitted`  n percent
                       1 15     0.3
                       3 35     0.7

From this, we can see that 70% of the random 50 data indices were predicted better by model 3 than by model 1. This helps demonstrate how a county’s state along with their median income helps predict the diabetes prevalence better than just with the median income.

This model appears to work best in terms of various numbers, such as \(R^2\) value and residuals and doesn’t appear to have many limitations at all. One limitation that may make predictions a bit less accurate is the distribution of number of counties in each state. Some of the states, like Arizona and Massachusetts have very few counties (15 and 14 respectively), particularly when compared with states like Georgia, who has 155 counties. Since we have added state as another predictor variable and it interacts with median income, the states’number of counties become relavant as they make more coefficients in the model. With that, states with more counties will have more accurate coefficients because there’s more data to train the model on, so the predicted values for those states will likely be more accurate than states with less counties (excluding outliers). Another thing to look at would be the normality of residuals, as it appears that this model isn’t as resilient to outlier counties. This is evident through each of the residual plots, as in the first one, there’s more variation as diabetes prevalence values increase and in the second one, the tails are farther away from the QQ line. A final limitation would be that by looking at US diabetes prevalence by state, Georgia and Massachusetts appear to be extreme states. Relative to the US median (9.8), Georgia has a diabetes prevalence noticeably higher (11.7) while Massachusetts is noticeably lower (7.7). The other states are all relatively close to the median value. With this, Georgia and Massachusetts may not be the best states to include in the data as it doesn’t help predict all US counties’ diabetes prevalence as well because they are outlier states.

9 Session Information

The session information.

sessionInfo()
R version 4.2.1 (2022-06-23)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Big Sur ... 10.16

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] mosaicData_0.20.3  ggformula_0.10.2   Matrix_1.5-1       lattice_0.20-45   
 [5] glue_1.6.2         patchwork_1.1.2    kableExtra_1.3.4   equatiomatic_0.3.1
 [9] broom_1.0.1        forcats_0.5.2      stringr_1.4.1      dplyr_1.0.10      
[13] purrr_0.3.4        readr_2.1.2        tidyr_1.2.0        tibble_3.1.8      
[17] ggplot2_3.3.6      tidyverse_1.3.2    naniar_0.6.1       janitor_2.1.0     
[21] rmdformats_1.0.4   knitr_1.40        

loaded via a namespace (and not attached):
  [1] googledrive_2.0.0   colorspace_2.0-3    deldir_1.0-6       
  [4] ellipsis_0.3.2      ggridges_0.5.3      visdat_0.5.3       
  [7] ggstance_0.3.5      snakecase_0.11.0    htmlTable_2.4.1    
 [10] base64enc_0.1-3     fs_1.5.2            rstudioapi_0.14    
 [13] farver_2.1.1        bit64_4.0.5         fansi_1.0.3        
 [16] lubridate_1.8.0     xml2_1.3.3          mosaic_1.8.4       
 [19] splines_4.2.1       cachem_1.0.6        polyclip_1.10-0    
 [22] Formula_1.2-4       jsonlite_1.8.0      cluster_2.1.3      
 [25] dbplyr_2.2.1        png_0.1-7           ggforce_0.3.4      
 [28] shiny_1.7.2         compiler_4.2.1      httr_1.4.4         
 [31] backports_1.4.1     assertthat_0.2.1    fastmap_1.1.0      
 [34] gargle_1.2.0        cli_3.4.1           tweenr_2.0.2       
 [37] later_1.3.0         htmltools_0.5.3     tools_4.2.1        
 [40] gtable_0.3.1        Rcpp_1.0.9          cellranger_1.1.0   
 [43] jquerylib_0.1.4     vctrs_0.4.1         nlme_3.1-157       
 [46] svglite_2.1.0       xfun_0.32           rvest_1.0.3        
 [49] mosaicCore_0.9.2    mime_0.12           lifecycle_1.0.1    
 [52] googlesheets4_1.0.1 MASS_7.3-57         scales_1.2.1       
 [55] vroom_1.5.7         hms_1.1.2           promises_1.2.0.1   
 [58] parallel_4.2.1      RColorBrewer_1.1-3  yaml_2.3.5         
 [61] gridExtra_2.3       sass_0.4.2          labelled_2.9.1     
 [64] rpart_4.1.16        latticeExtra_0.6-30 stringi_1.7.8      
 [67] highr_0.9           checkmate_2.1.0     rlang_1.0.5        
 [70] pkgconfig_2.0.3     systemfonts_1.0.4   evaluate_0.16      
 [73] labeling_0.4.2      htmlwidgets_1.5.4   bit_4.0.4          
 [76] tidyselect_1.1.2    plyr_1.8.7          magrittr_2.0.3     
 [79] bookdown_0.29       R6_2.5.1            generics_0.1.3     
 [82] Hmisc_4.7-1         DBI_1.1.3           mgcv_1.8-40        
 [85] pillar_1.8.1        haven_2.5.1         foreign_0.8-82     
 [88] withr_2.5.0         survival_3.3-1      nnet_7.3-17        
 [91] modelr_0.1.9        crayon_1.5.1        interp_1.1-3       
 [94] utf8_1.2.2          tzdb_0.3.0          rmarkdown_2.16     
 [97] jpeg_0.1-9          grid_4.2.1          readxl_1.4.1       
[100] data.table_1.14.2  
 [ reached getOption("max.print") -- omitted 8 entries ]
LS0tCnRpdGxlOiAiRGlhYmV0ZXMgUHJldmFsZW5jZSBBY3Jvc3MgR2VvZ3JhcGhpY2FsbHkgRGl2ZXJzZSBTdGF0ZXMgaW4gdGhlIFVTIgphdXRob3I6ICJNYXggVGplbiIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICBoaWdobGlnaHQ6IGthdGUKICAgIG51bWJlcl9zZWN0aW9uczogVFJVRQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCi0tLQoKIyBQcmVsaW1pbmFyaWVzCgpgYGB7ciBzZXR1cCwgZWNobz1GQUxTRSwgY2FjaGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkocm1kZm9ybWF0cykKCiMjIEdsb2JhbCBvcHRpb25zCm9wdGlvbnMobWF4LnByaW50PSIxMDAiKQpvcHRzX2NodW5rJHNldChjb21tZW50PU5BKQpvcHRzX2tuaXQkc2V0KHdpZHRoPTc1KQpgYGAKCiMjIFIgUGFja2FnZXMKCmBgYHtyIGxvYWRfcGFja2FnZXNfaGVyZSwgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkobmFuaWFyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShicm9vbSkKbGlicmFyeShlcXVhdGlvbWF0aWMpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZ2x1ZSkKYGBgCgojIyBEYXRhIEluZ2VzdApUbyBiZWdpbiwgd2UgcmVhZCB0aGUgZGF0YSBmcm9tIGEgY3N2IGZvcm1hdCBpbnRvIGEgdGliYmxlIHdpdGhpbiBSLCBza2lwcGluZyBvdmVyIHRoZSByb3cgY29udGFpbmluZyBkYXRhIGZvciB0aGUgZW50aXJlIFVTIGFuZCBrZWVwaW5nIG9ubHkgY291bnRpZXMgdGhhdCBhcmUgYWN0dWFsbHkgY291bnRpZXMgKHJhbmtlZCkuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KY2hyXzIwMjJfcmF3IDwtIHJlYWRfY3N2KCJhbmFseXRpY19kYXRhMjAyMi5jc3YiLCBza2lwID0gMSkgfD4gZmlsdGVyKGNvdW50eV9yYW5rZWQgPT0gMSkKYGBgCgoKCiMgRGF0YSBEZXZlbG9wbWVudAoKCiMjIFN0YXRlIFNlbGVjdGlvbgpOZXh0IGlzIHRoZSBzZWxlY3Rpb24gb2Ygc3RhdGVzIHRvIGludmVzdGlnYXRlIC0gSSd2ZSBzZWxlY3RlZCBBcml6b25hLCBHZW9yZ2lhLCBNYXNzYWNodXNldHRzLCBPaGlvLCBhbmQgV2FzaGluZ3Rvbi4gSSd2ZSBwaWNrZWQgdGhlc2Ugc3RhdGVzIGJlY2F1c2UgSSB3YW50ZWQgdG8gZ2V0IGEgZ29vZCBkaXN0cmlidXRpb24gb2YgYXJlYXMgYWNyb3NzIHRoZSBVUywgc28gZWFjaCBzdGF0ZSBsb2NhdGlvbi13aXNlIGlzIHF1aXRlIGRpZmZlcmVudCB0aGFuIHRoZSBvdGhlcnMuIEZ1cnRoZXJtb3JlLCBJIHBpY2tlZCBzdGF0ZXMgdGhhdCBoYWQgc2ltaWxhciBwb3B1bGF0aW9ucywgYXMgYWxsIGZpdmUgc3RhdGVzIHJhbmtlZCBiZXR3ZWVuIDcgYW5kIDE1IGluIHRlcm1zIG9mIHBvcHVsYXRpb24uIFRoZSB0b3RhbCBhbW91bnQgb2YgY291bnRpZXMgd2FzIDMxNSwgZmFsbGluZyB3aXRoaW4gdGhlIHJhbmdlIG5lZWRlZCwgd2l0aCBBcml6b25hIGhhdmluZyAxNSwgR2VvcmdpYSBoYXZpbmcgMTU5LCBNYXNzYWNodXNldHRzIGhhdmluZyAxNCwgT2hpbyBoYXZpbmcgODgsIGFuZCBXYXNoaW5ndG9uIGhhdmluZyAzOSBjb3VudGllcyByZXNwZWN0aXZlbHkuCgpgYGB7cn0KIyBzZWxlY3Qgc3RhdGVzCmNocl8yMDIyIDwtIGNocl8yMDIyX3JhdyB8PgogIGZpbHRlcihzdGF0ZSA9PSAiT0giIHwgc3RhdGUgPT0gIkdBIiB8IHN0YXRlID09ICJNQSIgfCBzdGF0ZSA9PSAiV0EiIHwgc3RhdGUgPT0gIkFaIikKCiMgY291bnRpZXMgYnkgc3RhdGUKY2hyXzIwMjIgfD4gdGFieWwoc3RhdGUpCgojIHRpYmJsZSBkaW1lbnNpb25zCmRpbShjaHJfMjAyMikKYGBgCgojIyBWYXJpYWJsZSBTZWxlY3Rpb24KQWxvbmcgd2l0aCB0aGUgZm91ciByZXF1aXJlZCB2YXJpYWJsZXMgKGZpcHNjb2RlLCBjb3VudHksIHN0YXRlLCBhbmQgY291bnR5X3JhbmtlZCksIHdlIGhhZCB0byBzZWxlY3QgZml2ZSBtb3JlIHZhcmlhYmxlcy4gV2Ugc2VsZWN0ZWQgZGlhYmV0ZXMgcHJldmFsZW5jZSAodjA2MF9yYXd2YWx1ZSkgdG8gYmUgdGhlIG91dGNvbWUgdmFyaWFibGUsIG1lZGlhbiBpbmNvbWUgKHYwNjNfcmF3dmFsdWUpIGFuZCBhZHVsdCBzbW9raW5nICh2MDA5X3Jhd3ZhbHVlKSB0byBiZSBxdWFudGl0YXRpdmUgdmFyaWFibGVzLCBleGNlc3NpdmUgZHJpbmtpbmcgKHYwNDlfcmF3dmFsdWUpIHRvIGJlIHRoZSBiaW5hcnkgdmFyaWFibGUsIGFuZCBsaW1pdGVkIGFjY2VzcyB0byBoZWFsdGh5IGZvb2RzIHRvIGJlIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSAodjA4M19yYXd2YWx1ZSkuIERpYWJldGVzIHByZXZhbGVuY2Ugd2FzIGNob3NlbiBhcyBvYmVzaXR5IGhhcyBiZWVuIHNpZ25pZmljYW50bHkgaW5jcmVhc2luZyByZWNlbnRseSBhcm91bmQgdGhlIHdvcmxkLCBwYXJ0aWN1bGFybHkgaW4gdGhlIFVTLiBNZWRpYW4gaW5jb21lIHdhcyBjaG9zZW4gYXMgaXQgaGFzIGJlZW4gd2VsbCBkb2N1bWVudGVkIHRoYXQgcGVvcGxlIHdpdGggbG93ZXIgaW5jb21lIGFyZSBhdCBoaWdoZXIgcmlzayBvZiBoYXZpbmcgZGlhYmV0ZXMuIEFkdWx0IHNtb2tpbmcgd2FzIGNob3NlbiBiZWNhdXNlIHNpbWlsYXIgdG8gaW5jb21lLCBpdCdzIGJlZW4gZm91bmQgdG8gaW5jcmVhc2Ugb25lJ3MgY2hhbmNlcyBvZiBoYXZpbmcgZGlhYmV0ZXMuIEV4Y2Vzc2l2ZSBkcmlua2luZyB3YXMgc2VsZWN0ZWQgYXMgaXQgYWxzbyBoYXMgYmVlbiBmb3VuZCB0byBpbmNyZWFzZSB0aGUgcmlzayBvZiBkaWFiZXRlcy4gTGFzdGx5LCBsaW1pdGVkIGFjY2VzcyB0byBoZWFsdGh5IGZvb2RzIHdhcyBzZWxlY3RlZCBhcyBpZiBvbmUgZGlkbid0IGhhdmUgYWNjZXNzIHRvIGhlYWx0aHkgZm9vZHMsIHRoZXkgd291bGQgYmUgbW9yZSBwcm9uZSB0byBidXlpbmcgdW5oZWFsdGh5IG9uZXMgdGhhdCB3b3VsZCBsZWFkIHRvIGhpZ2hlciBjaGFuY2VzIG9mIG9iZXNpdHkgYW5kIGRpYWJldGVzLiBFYWNoIHZhcmlhYmxlIGhhZCB0byBiZSBhZGp1c3RlZCBhY2NvcmRpbmcgKHNjYWxpbmcgd2lzZSkgdG8gYmVjb21lIGFuIGFwcHJvcHJpYXRlIHZhbHVlLCBzdWNoIGFzIGEgcGVyY2VudC4gRm9yIGV4Y2Vzc2l2ZSBkcmlua2luZywgdGhlIGN1dG9mZiBjaG9zZW4gYmV0d2VlbiBhIDAgYW5kIDEgdmFsdWUgd2FzIHRoZSBtZWFuIGV4Y2Vzc2l2ZSBkcmlua2luZyBwZXJjZW50YWdlLiBGb3IgbGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcywgZWFjaCBjYXRlZ29yeSB3YXMgZXZlbmx5IHNwbGl0IGFzIHRvIGhvdyBtYW55IGNvdW50aWVzIHdlcmUgaW4gZWFjaC4KCmBgYHtyfQojIHNlbGVjdCB2YXJpYWJsZXMKY2hyXzIwMjIgPC0gY2hyXzIwMjIgfD4KICBzZWxlY3QoZmlwc2NvZGUsIGNvdW50eSwgc3RhdGUsIGNvdW50eV9yYW5rZWQsIHYwNjBfcmF3dmFsdWUsIHYwNjNfcmF3dmFsdWUsIHYwMDlfcmF3dmFsdWUsIAogICAgICAgICB2MDQ5X3Jhd3ZhbHVlLCB2MDgzX3Jhd3ZhbHVlKSB8PgogIHJlbmFtZShkaWFiZXRlc19wcmV2YWxlbmNlID0gdjA2MF9yYXd2YWx1ZSwgCiAgICAgICAgIG1lZGlhbl9pbmNvbWUgPSB2MDYzX3Jhd3ZhbHVlLAogICAgICAgICBhZHVsdF9zbW9raW5nID0gdjAwOV9yYXd2YWx1ZSwKICAgICAgICAgZXhjZXNzaXZlX2RyaW5raW5nID0gdjA0OV9yYXd2YWx1ZSwKICAgICAgICAgbGltaXRlZF9hY2Nlc3NfaGVhbHRoeV9mb29kcyA9IHYwODNfcmF3dmFsdWUpIHw+CiAgbXV0YXRlKGRpYWJldGVzX3ByZXZhbGVuY2UgPSBkaWFiZXRlc19wcmV2YWxlbmNlICogMTAwLAogICAgICAgICBtZWRpYW5faW5jb21lID0gbWVkaWFuX2luY29tZSAvIDEwMDAsCiAgICAgICAgIGFkdWx0X3Ntb2tpbmcgPSBhZHVsdF9zbW9raW5nICogMTAwLAogICAgICAgICBleGNlc3NpdmVfZHJpbmtpbmcgPSBleGNlc3NpdmVfZHJpbmtpbmcgKiAxMDAsCiAgICAgICAgIGxpbWl0ZWRfYWNjZXNzX2hlYWx0aHlfZm9vZHMgPSBsaW1pdGVkX2FjY2Vzc19oZWFsdGh5X2Zvb2RzICogMTAwKQpgYGAKCgojIyBWYXJpYWJsZXMgdG8gRmFjdG9ycwpGb3IgdmFyaWFibGUgNCAoZXhjZXNzaXZlX2RyaW5raW5nKSwgd2UgbWFkZSBpdCBhIGJpbmFyeSB2YXJpYWJsZSByYXRoZXIgdGhhbiBrZWVwIGl0IHF1YW50aXRhdGl2ZS4gVG8gc3BsaXQgdmFsdWVzIGludG8gdHdvIGRpc3RpbmN0IGNhdGVnb3JpZXMsIHRoZSBtZWFuIHZhbHVlIHdhcyB1c2VkIGFzIGEgY3V0b2ZmLCB3aXRoIHZhbHVlcyBvZiBwZXJjZW50YWdlcyBiZWxvdyB0aGUgbWVhbiBzZXQgdG8gMCwgYW5kIG90aGVyd2lzZSBzZXQgdG8gMS4gVGhlIDV0aCB2YXJpYWJsZSAobGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcykgd2FzIGFsc28gbWFkZSBjYXRlZ29yaWNhbCwgaG93ZXZlciB0aGlzIHRpbWUgaXQncyBtdWx0aS1jYXRlZ29yaWNhbCByYXRoZXIgdGhhbiBiaW5hcnkuIFRvIGFjaGlldmUgdGhpcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHRoZSBjYXRlZ29yaWVzIHdvdWxkIGhhdmUgYW4gYXBwcm9wcmlhdGUgYW1vdW50IG9mIHZhbHVlcywgd2UgdXNlZCB0aGUgY3V0MiBmdW5jdGlvbiwgd2hpY2ggc3BsaXQgdXAgdmFsdWVzIGludG8gY2F0ZWdvcmllcyBzdWNoIHRoYXQgZWFjaCBjYXRlZ29yeSBoYXMgdGhlIHNhbWUgYW1vdW50IG9mIHZhbHVlcy4gQWZ0ZXIgZmluZGluZyB3aGF0IHRoZSBpbnRlcnZhbHMgd2VyZSBmb3IgZWFjaCBjYXRlZ29yeSwgZWFjaCBvbmUgd2FzIHJlZmFjdG9yZWQgaW50byBudW1lcmljYWwgdmFsdWVzLCByYW5naW5nIGZyb20gMC01LCBhbGJlaXQgd2l0aCBzb21lIE5BIHZhbHVlcyB0aGF0IHdlcmVuJ3QgZmFjdG9yZWQgaW4uCgpgYGB7cn0KY2hyXzIwMjIgPC0gY2hyXzIwMjIgfD4KICAgIG11dGF0ZShmaXBzY29kZSA9IHN0cl9wYWQoZmlwc2NvZGUsIDUsIHBhZCA9ICIwIiksCiAgICAgICAgICAgc3RhdGUgPSBmYWN0b3Ioc3RhdGUpKQoKIyBtYWtlIGV4Y2Vzc2l2ZV9kcmlua2luZyBhIGJpbmFyeSB2YXJpYWJsZQpjaHJfMjAyMiA8LSBjaHJfMjAyMiB8PgogICAgbXV0YXRlKGV4Y2Vzc2l2ZV9kcmlua2luZ19jYXQgPSBjYXNlX3doZW4oCiAgICAgICAgICAgICAgICAgICBleGNlc3NpdmVfZHJpbmtpbmcgPCBtZWFuKGV4Y2Vzc2l2ZV9kcmlua2luZykgfiAwLCBUUlVFIH4gMSksCiAgICAgICAgICAgZXhjZXNzaXZlX2RyaW5raW5nX2NhdCA9IGZhY3RvcihleGNlc3NpdmVfZHJpbmtpbmdfY2F0KSkKCiMgbWFrZSBsaW1pdGVkIGFjY2VzcyB0byBoZWFsdGh5IGZvb2RzIGNhdGVnb3JpY2FsCmNocl8yMDIyIDwtIGNocl8yMDIyIHw+CiAgICBtdXRhdGUobGltaXRlZF9oZWFsdGh5X2NhdCA9IGZhY3RvcihIbWlzYzo6Y3V0MihsaW1pdGVkX2FjY2Vzc19oZWFsdGh5X2Zvb2RzLCBnID0gNSkpKQoKIyBzZWUgaW50ZXJ2YWxzIGZvciBjYXRlZ29yaWVzCnVuaXF1ZShjaHJfMjAyMlsibGltaXRlZF9oZWFsdGh5X2NhdCJdKQoKIyByZWNvZGUgZmFjdG9yIHZhbHVlcwpjaHJfMjAyMiA8LSBjaHJfMjAyMiB8PgogICAgbXV0YXRlKGxpbWl0ZWRfaGVhbHRoeV9jYXQgPSBmY3RfcmVjb2RlKGxpbWl0ZWRfaGVhbHRoeV9jYXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxvd2VzdCIgPSAiWyAwLjAwLCAyLjc2KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxvdyIgPSAiWyAyLjc2LCA1LjUxKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1pZGRsZSIgPSAiWyA1LjUxLCA4LjM5KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImhpZ2giID0gIlsgOC4zOSwxMi41MSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoaWdoZXN0IiA9ICJbMTIuNTEsNDcuNDNdIikpCmBgYAoKIyMjIENoZWNraW5nIHZhbHVlIGRpc3RyaWJ1dGlvbnMKCmBgYHtyfQpjaHJfMjAyMiB8PiB0YWJ5bChleGNlc3NpdmVfZHJpbmtpbmdfY2F0KQpjaHJfMjAyMiB8PiB0YWJ5bChsaW1pdGVkX2hlYWx0aHlfY2F0KQoKIyBnZXQgc3RydWN0dXJlCnN0cihjaHJfMjAyMikKYGBgCgoKIyMgUmV2aXNpbmcgT3JkZXIgb2YgVmFyaWFibGVzCgpgYGB7cn0KY2hyXzIwMjIgPC0gY2hyXzIwMjIgfD4gcmVsb2NhdGUoY291bnR5X3JhbmtlZCwgLmFmdGVyID0gbGFzdF9jb2woKSkKYGBgCgoKCiMjIFRocmVlIEltcG9ydGFudCBDaGVja3MKMSkgNzUlIGNvbXBsZXRlbmVzcyBvZiBkYXRhIGZvciBlYWNoIHN0YXRlCjIpIFJhdyB2ZXJzaW9ucyBvZiB2YXJpYWJsZXMgbXVzdCBoYXZlIGF0IGxlYXN0IDEwIGRpc3RpbmN0IG5vbi1taXNzaW5nIHZhbHVlcwozKSAxMCBjb3VudGllcyBpbiBlYWNoIGNhdGVnb3J5IGZvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKCmBgYHtyfQojIGNoZWNrIGNvbXBsZXRlbmVzcyAoMSkKY2hyXzIwMjIgfD4gbWlzc192YXJfc3VtbWFyeSgpCgojIGVuc3VyZSBubyBpc3N1ZXMKbW9zYWljOjpmYXZzdGF0cyhsaW1pdGVkX2FjY2Vzc19oZWFsdGh5X2Zvb2RzIH4gc3RhdGUsIGRhdGEgPSBjaHJfMjAyMikgfD4KICBzZWxlY3Qoc3RhdGUsIG4sIG1pc3NpbmcpIHw+CiAgbXV0YXRlKHBjdF9hdmFpbGFibGUgPSAxMDAgKiAobiAtIG1pc3NpbmcpIC8gbikgfD4KICBrYWJsZSgpCgojIGNoZWNrIGRpc3RpbmN0cyAoMikKY2hyXzIwMjIgfD4gc3VtbWFyaXplKGFjcm9zcyhkaWFiZXRlc19wcmV2YWxlbmNlOmxpbWl0ZWRfYWNjZXNzX2hlYWx0aHlfZm9vZHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIH5uX2Rpc3RpbmN0KC4pKSkKCiMgY2hlY2sgYW1vdW50IG9mIGNvdW50aWVzIGZvciBlYWNoIGNhdGVnb3JpY2FsIHZhcmlhYmxlICgzKQpjaHJfMjAyMiB8PiB0YWJ5bChleGNlc3NpdmVfZHJpbmtpbmdfY2F0KQpjaHJfMjAyMiB8PiB0YWJ5bChsaW1pdGVkX2hlYWx0aHlfY2F0KQpgYGAKCgoKIyBPdXIgQW5hbHl0aWMgVGliYmxlCgoKIyMgUHJpbnRpbmcgYW5kIFN1bW1hcml6aW5nCldlIGhhdmUgdG8gZGVtb25zdHJhdGUgYSBmZXcgdGhpbmdzIGFib3V0IG91ciBkYXRhLiBUaGlzIGluY2x1ZGVzIHByaW50aW5nIHRoZSB0aWJibGUsIHNob3dpbmcgdGhhdCBlYWNoIHF1YW50aXRhdGl2ZSB2YXJpYWJsZSBoYXMgYXQgbGVhc3QgMTUgZGlzdGluY3QgdmFsdWVzLCBhbmQgdGhhdCBlYWNoIHN0YXRlIGhhcyBhdCBsZWFzdCA3NSUgY29tcGxldGVuZXNzIG9mIGRhdGEuCgpgYGB7cn0KY2hyXzIwMjIKCkhtaXNjOjpkZXNjcmliZShjaHJfMjAyMikKCiMgc2VlIG51bWJlciBvZiBkaXN0aW5jdCB2YWx1ZXMgcGVyIGNvbHVtbgpjaHJfMjAyMiB8PiBzdW1tYXJpemUoYWNyb3NzKGRpYWJldGVzX3ByZXZhbGVuY2U6bGltaXRlZF9oZWFsdGh5X2NhdCwgfm5fZGlzdGluY3QoLikpKQoKIyBzZWUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzIGZvciBlYWNoIHN0YXRlIC0+IGFsbCBhYm92ZSA3NSUgY29tcGxldGVuZXNzCmNocl8yMDIyIHw+IGZpbHRlcihzdGF0ZSA9PSAiQVoiKSB8PiBtaXNzX3Zhcl9zdW1tYXJ5KCkKY2hyXzIwMjIgfD4gZmlsdGVyKHN0YXRlID09ICJHQSIpIHw+IG1pc3NfdmFyX3N1bW1hcnkoKQpjaHJfMjAyMiB8PiBmaWx0ZXIoc3RhdGUgPT0gIk9IIikgfD4gbWlzc192YXJfc3VtbWFyeSgpCmNocl8yMDIyIHw+IGZpbHRlcihzdGF0ZSA9PSAiTUEiKSB8PiBtaXNzX3Zhcl9zdW1tYXJ5KCkKY2hyXzIwMjIgfD4gZmlsdGVyKHN0YXRlID09ICJXQSIpIHw+IG1pc3NfdmFyX3N1bW1hcnkoKQoKIyBudW1iZXIgb2YgdmFsdWVzIHBlciBjYXRlZ29yeSAtPiBzZWUgdGFzayA0LCBjaGVja2luZyB2YWx1ZSBkaXN0cmlidXRpb25zCgojIHN0YXRpc3RpY3Mgb24gcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyBhbmQgb3JpZ2luYWwgdmVyc2lvbnMgb2YgYmluYXJ5IGFuZCBjYXRlZ29yaWNhbCAKbW9zYWljOjpmYXZzdGF0cyh+ZGlhYmV0ZXNfcHJldmFsZW5jZSwgZGF0YSA9IGNocl8yMDIyKQptb3NhaWM6OmZhdnN0YXRzKH5tZWRpYW5faW5jb21lLCBkYXRhID0gY2hyXzIwMjIpCm1vc2FpYzo6ZmF2c3RhdHMofmFkdWx0X3Ntb2tpbmcsIGRhdGEgPSBjaHJfMjAyMikKbW9zYWljOjpmYXZzdGF0cyh+ZXhjZXNzaXZlX2RyaW5raW5nLCBkYXRhID0gY2hyXzIwMjIpCm1vc2FpYzo6ZmF2c3RhdHMofmxpbWl0ZWRfYWNjZXNzX2hlYWx0aHlfZm9vZHMsIGRhdGEgPSBjaHJfMjAyMikKCiMgc2hvdyB2YWx1ZSBkaXN0cmlidXRpb25zIGZvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKY2hyXzIwMjIgfD4gdGFieWwoc3RhdGUpCmNocl8yMDIyIHw+IHRhYnlsKGV4Y2Vzc2l2ZV9kcmlua2luZ19jYXQpCmNocl8yMDIyIHw+IHRhYnlsKGxpbWl0ZWRfaGVhbHRoeV9jYXQpCmBgYAoKIyMgU2F2aW5nIGFuZCBTaGFyaW5nCldlIHdpbGwgc2F2ZSB0aGUgZGF0YSBhcyBhbiBSIGRhdGFzZXQgaW50byB0aGUgc2FtZSBmb2xkZXIgYXMgdGhlIHByb2plY3QgcHJvcG9zYWwuCgpgYGB7cn0KY2hyXzIwMjIKCiMgc2F2ZSBmaWxlIGFzIFIgZGF0YXNldApzYXZlUkRTKGNocl8yMDIyLCBmaWxlID0gImNocl8yMDIyX01heF9UamVuLlJkcyIpCmBgYAoKCiMgQ29kZWJvb2sKV2UgYWxzbyBoYXZlIHRvIGNyZWF0ZSBjb2RlYm9va3MgZm9yIGVhY2ggc3RhdGUgYW5kIHZhcmlhYmxlLiBGb3IgdGhlIHN0YXRlIGNvZGVib29rLCBpbmZvcm1hdGlvbiBhYm91dCBlYWNoIHN0YXRlJ3MgbmFtZSwgYWJicmV2aWF0aW9uLCBhbmQgbnVtYmVyIG9mIGNvdW50aWVzIGlzIHByb3ZpZGVkLiBGb3IgdGhlIHZhcmlhYmxlIGNvZGVib29rLCBpbmZvcm1hdGlvbiBhYm91dCBlYWNoIHZhcmlhYmxlJ3MgbmFtZSwgZGVzY3JpcHRpb24sIG9yaWdpbmFsIHZhcmlhYmxlIG5hbWUsIGFuZCBudW1iZXIgb2YgbWlzc2luZyB2YWx1ZXMgaXMgcHJvdmlkZWQuCgpgYGB7cn0KIyBnZXQgYW1vdW50IG9mIGNvdW50aWVzIGJ5IHN0YXRlCmNocl8yMDIyIHw+IGNvdW50KHN0YXRlKQoKIyBnZXQgYW1vdW50IG9mIG1pc3NpbmcgdmFsdWVzIGJ5IGNvbHVtbgpjaHJfMjAyMiB8PiBtaXNzX3Zhcl9zdW1tYXJ5KCkKCiMgZ2V0IG1lZGlhbiB2YWx1ZSBjdXRvZmYgb2YgdW5lbXBsb3ltZW50IHBlcmNlbnRhZ2UgCnN1bW1hcnkoY2hyXzIwMjJbImV4Y2Vzc2l2ZV9kcmlua2luZyJdKQpgYGAKCiMjIFN0YXRlIFRhYmxlCgpzdGF0ZSB8IGFiYnJldmlhdGlvbiB8ICMgb2YgY291bnRpZXMKLS0tLS0tfC0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tCkFyaXpvbmEgfCBBWiB8IDE1Ckdlb3JnaWEgfCBHQSB8IDE1OQpNYXNzYWNodXNldHRzIHwgTUEgfCAxNApPaGlvIHwgT0ggfCA4OApXYXNoaW5ndG9uIHwgV0EgfCAzOQotfC18LQpUb3RhbCB8IC0gfCAzMTUKCiMjIFZhcmlhYmxlIFRhYmxlCgpWYXJpYWJsZSB8IERlc2NyaXB0aW9uIHwgT3JpZ2luYWwgVmFyaWFibGUgfCAjIE1pc3NpbmcgVmFsdWVzCi0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0KZmlwc2NvZGUgfCA1LWRpZ2l0IEZJUFMgY29kZSB8IGZpcHNjb2RlIHwgMApjb3VudHkgfCBuYW1lIHwgY291bnR5IHwgMApzdGF0ZSB8IHN0YXRlIGFiYnJldmlhdGlvbiB8IHN0YXRlIHwgMApjb3VudHlfcmFua2VkIHwgY291bnR5IHJhbmtlZCAoeWVzID0gMSwgbm8gPSAwKSB8IGNvdW50eV9yYW5rZWQgfCAwCmRpYWJldGVzX3ByZXZhbGVuY2UgfCBbb3V0Y29tZV0gZGlhYmV0ZXMgcHJldmFsZW5jZSBwZXJjZW50YWdlIHwgdjA2MF9yYXd2YWx1ZSB8IDAKbWVkaWFuX2luY29tZSB8IFtxdWFudGl0YXRpdmVdIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGluIHRob3VzYW5kcyB8IHYwNjNfcmF3dmFsdWUgfCAwCmFkdWx0X3Ntb2tpbmcgfCBbcXVhbnRpdGF0aXZlXSBhZHVsdCBzbW9raW5nIHBlcmNlbnRhZ2UgfCB2MDA5X3Jhd3ZhbHVlIHwgMApleGNlc3NpdmVfZHJpbmtpbmcgfCBleGNlc3NpdmUgZHJpbmtpbmcgcGVyY2VudGFnZSB8IHYwNDlfcmF3dmFsdWUgfCAwIHwgW2JpbmFyeV0KbGltaXRlZF9hY2Nlc3NfaGVhbHRoeV9mb29kcyB8IGxpbWl0ZWQgYWNjZXNzIHRvIGhlYWx0aHkgZm9vZHMgcGVyY2VudGFnZSB8IHYwODNfcmF3dmFsdWUgfCA1CmV4Y2Vzc2l2ZV9kcmlua2luZ19jYXQgfCBbY2F0ZWdvcmljYWxdIDIgY2F0ZWdvcmllczogMCBpZiB2YWx1ZSA8IDE4LjAyLCAxIGlmIG90aGVyd2lzZSAoc2VlIHRhc2sgNCBmb3IgaG93IHZhbHVlcyB0byBzcGxpdCB2YXJpYWJsZSB3YXMgY2hvc2VuKSB8IHYwNDlfcmF3dmFsdWUgfCAwCmxpbWl0ZWRfaGVhbHRoeV9jYXQgfCBbY2F0ZWdvcmljYWxdIDUgY2F0ZWdvcmllczogJ2xvd2VzdCcgaWYgdmFsdWUgPDIuNzYsICdsb3cnIGlmIDIuNzYgPD0gdmFsdWUgPCA1LjUxLCAnbWlkZGxlJyBpZiA1LjUxIDw9IHZhbHVlIDwgOC4zOSwgJ2hpZ2gnIGlmIDguMzkgPD0gdmFsdWUgPCAxMi41MSwgJ2hpZ2hlc3QnIGlmIDEyLjUxIDw9IHZhbHVlIDw9IDQ3LjQzIChzZWUgdGFzayA0IGZvciBob3cgdmFsdWVzIHRvIHNwbGl0IHZhcmlhYmxlIHdhcyBjaG9zZW4pIHwgdjA4M19yYXd2YWx1ZSB8IDUKCgojIEJpZ2dlc3QgQ2hhbGxlbmdlClRoZSBtb3N0IGNoYWxsZW5naW5nIHBhcnQgb2YgdGhlIHByb2plY3Qgc28gZmFyIGZvciBtZSB3YXMgdG8gY29udmVydCB0aGUgbGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcyB2YXJpYWJsZSBpbnRvIGEgbXVsdGktY2F0ZWdvcmljYWwgdmFyaWFibGUuIFRoZSBwcm9jZXNzIHdhc24ndCB0b28gaGFyZCwgbW9yZSBzbyBqdXN0IHRoZSBiZXN0IHdheSB0byBkbyBpdC4gRm9yIGV4YW1wbGUsIGluIHRoZSBiZWdpbm5pbmcsIEkgd2FudGVkIHRvIHVzZSBzcGVjaWZpZWQgdmFsdWVzIHRvIGJlIGN1dG9mZnMuIEhvd2V2ZXIsIGJlY2F1c2Ugb2YgdGhlIHJlcXVpcmVtZW50IG9mIGhhdmluZyBhdCBsZWFzdCAxMCBjb3VudGllcyBpbiBlYWNoIGNhdGVnb3J5LCB0aGlzIHdhc24ndCBwb3NzaWJsZSBiZWNhdXNlIG9mIHRoZSByYW5nZSBvZiBkYXRhIGFuZCB0aGUgZGlzdHJpYnV0aW9uLiBUaGVyZSB3ZXJlIGEgY291cGxlIG9mIG90aGVyIG1ldGhvZHMgSSBmbGlydGVkIHdpdGgsIGJ1dCBlYWNoIG9mIHRoZW0gaGFkIHNvbWUgc29ydCBvZiBkb3duZmFsbCB0aGF0IGxlZCB0byB0aGVtIGJlaW5nIHRvc3NlZCBvdXQuIEF0IHRoZSBlbmQgb2YgdGhlIGRheSwgSSB3ZW50IHdpdGggYSBzaW1wbGUgZXZlbiBjdXQsIHdoZXJlIHRoZSBjdXQyIGZ1bmN0aW9uIGRpdmlkZWQgZWFjaCBjYXRlZ29yeSBldmVubHkgc28gdGhhdCBlYWNoIG9uZSBjb25zaXN0cyBvZiB0aGUgc2FtZSBhbW91bnQgb2YgY291bnRpZXMgKCstMSkuIAoKCiMgQW5hbHlzaXMgMQoKIyMgVmFyaWFibGVzCldlIHdpbGwgYmUgdXNpbmcgbWVkaWFuX2luY29tZSBhcyB0aGUgcXVhbnRpdGF0aXZlIHByZWRpY3RvciB2YXJpYWJsZSBhbmQgZGlhYmV0ZXNfcHJldmFsZW5jZSBhcyB0aGUgb3V0Y29tZSB2YXJpYWJsZS4gVGhlIG1lZGlhbl9pbmNvbWUgdmFyaWFibGUgbWVhc3VyZXMgdGhlIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGluIHRob3VzYW5kcyBvZiBkb2xsYXJzIG9mIHJlc2lkZW50cyBpbiB0aGUgY291bnR5IGFuZCB0aGUgZGlhYmV0ZXNfcHJldmFsZW5jZSB2YXJpYWJsZSBtZWFzdXJlcyB0aGUgZGlhYmV0ZXMgcHJldmFsZW5jZSBwZXJjZW50YWdlIG9mIHJlc2lkZW50cyBpbiB0aGUgY291bnR5LiBGcm9tIG91ciB0aWJibGUgKGNocl8yMDIyKSwgdGhlIHZhcmlhYmxlcyBhcmUgbGlzdGVkIGFzIG1lZGlhbl9pbmNvbWUgKHByZWRpY3RvcikgYW5kIGRpYWJldGVzX3ByZXZhbGVuY2UgKG91dGNvbWUpIGFjcm9zcyB0aGUgc3RhdGVzIG9mIEFyaXpvbmEsIEdlb3JnaWEsIE1hc3NhY2h1c2V0dHMsIE9oaW8sIGFuZCBXYXNoaW5ndG9uLCBhbmQgZWFjaCB2YXJpYWJsZSBoYXMgMzE1IGNvdW50aWVzIHdpdGggY29tcGxldGUgZGF0YS4gRm9yIEN1eWFob2dhIENvdW50eSwgT2hpbywgdGhlIHZhbHVlcyBvZiB0aGUgcHJlZGljdG9yIGFuZCBvdXRjb21lIHZhcmlhYmxlIGFyZSBtZWRpYW5faW5jb21lID0gNTUuMTI4IGFuZCBkaWFiZXRlc19wcmV2YWxlbmNlID0gMTEuMS4KCmBgYHtyfQojIG9ubHkgZ2V0IG1lZGlhbl9pbmNvbWUgYW5kIGRpYWJldGVzX3ByZXZhbGVuY2UKYTFfZGF0YSA8LSBjaHJfMjAyMiB8PiAKICBzZWxlY3QobWVkaWFuX2luY29tZSwgZGlhYmV0ZXNfcHJldmFsZW5jZSkgfD4gCiAgZmlsdGVyKGNvbXBsZXRlLmNhc2VzKG1lZGlhbl9pbmNvbWUsIGRpYWJldGVzX3ByZXZhbGVuY2UpKQoKZGltKGExX2RhdGEpCgojIGdldCB2YWx1ZXMgZm9yIEN1eWFob2dhIENvdW50eQpjaHJfMjAyMiB8PiBmaWx0ZXIoc3RhdGUgPT0gIk9IIikgfD4KICBmaWx0ZXIoY291bnR5ID09ICJDdXlhaG9nYSBDb3VudHkiKSB8PgogIHNlbGVjdChtZWRpYW5faW5jb21lLCBkaWFiZXRlc19wcmV2YWxlbmNlKQpgYGAKCiMjIFJlc2VhcmNoIFF1ZXN0aW9uCkhvdyB3ZWxsIGRvZXMgYSBjb3VudHkncyBtZWRpYW4gaW5jb21lIHByZWRpY3QgdGhlaXIgZGlhYmV0ZXMgcHJldmFsZW5jZSBpbiAzMTUgY291bnRpZXMgYWNyb3NzIHRoZSBzdGF0ZXMgb2YgQXJpem9uYSwgR2VvcmdpYSwgTWFzc2FjaHVzZXR0cywgT2hpbywgYW5kIFdhc2hpbmd0b24/CgojIyBEYXRhIFZpc3VhbGl6YXRpb24KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KZ2dwbG90KGExX2RhdGEsIGFlcyh4ID0gbWVkaWFuX2luY29tZSwgeSA9IGRpYWJldGVzX3ByZXZhbGVuY2UpKSArCiAgZ2VvbV9wb2ludChjb2wgPSAiYmxhY2siKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJyZWQiLCBzZSA9IEZBTFNFKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGNvbCA9ICJibHVlIiwgc2UgPSBGQUxTRSkgKyAKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBCZXR3ZWVuIE1lZGlhbiBJbmNvbWUgYW5kIERpYWJldGVzIFByZXZhbGVuY2UiLAogICAgICAgeCA9ICJNZWRpYW4gSW5jb21lIG9mIENvdW50eSBpbiBUaG91c2FuZHMgb2YgRG9sbGFycyIsCiAgICAgICB5ID0gIkRpYWJldGVzIFByZXZhbGVuY2UgUGVyY2VudGFnZSBvZiBDb3VudHkiKQpgYGAKCkZyb20gdGhpcyBwbG90LCBpdCBhcHBlYXJzIHRoYXQgdGhlcmUgaXMgYSBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGNvdW50aWVzJyBtZWRpYW4gaW5jb21lIGFuZCBkaWFiZXRlcyBwcmV2YWxlbmNlLiBXaGlsZSB0aGUgdmFyaWFibGUgcmVsYXRpb25zaGlwIGxvb2tzIHByZXR0eSBsaW5lYXIsIHRoZXJlIGFwcGVhcnMgdG8gYmUgYSBjdXJ2ZSwgd2hpY2ggaW5kaWNhdGVzIHRoYXQgdGhlcmUgaXMgc29tZSBza2V3IGluIHRoZSBkYXRhLiBUaGlzIG1heSBtZWFuIHRoYXQgYSB0cmFuc2Zvcm1hdGlvbiBtYXkgYmUgbmVlZGVkIGJlZm9yZSBydW5uaW5nIGEgbGluZWFyIG1vZGVsIG9uIHRoZSBkYXRhLgoKCiMjIFRyYW5zZm9ybWF0aW9uIEFzc2Vzc21lbnQKCldoZW4gbG9va2luZyBhdCB0cmFuc2Zvcm1hdGlvbnMsIHdlIGxvb2tlZCBhdCB1c2luZyBhIGxvZ2FyaXRobSwgYW4gaW52ZXJzZSwgb3IgYSBzcXVhcmUgdHJhbnNmb3JtYXRpb24gb24gdGhlIG91dGNvbWUgdmFyaWFibGUgKGRpYWJldGVzIHByZXZhbGVuY2UpLiBUbyBldmFsdWF0ZSBlYWNoIG9mIHRoZW0sIGEgUVEgcGxvdCB3YXMgdXNlZCBhbmQgY29tcGFyZWQgd2l0aCB0aGUgb3RoZXIgdHJhbnNmb3JtYXRpb25zLCBpbmNsdWRpbmcgYSBRUSBwbG90IG9mIHRoZSB1bnRyYW5zZm9ybWVkIGRhdGEuIEZyb20gdGhlc2UgcGxvdHMsIGl0IGFwcGVhcmVkIHRoYXQgYSBsb2dhcml0aG0gdHJhbnNmb3JtYXRpb24gYXBwZWFycyB0byB3b3JrIGJlc3Qgd2l0aCB0aGlzIHN1YnNldCBvZiBkYXRhLCBhcyB0aGUgZGF0YSBmb2xsb3dlZCB0aGUgUVEgbGluZSB0aGUgYmVzdC4gQWx0aG91Z2ggdGhlIGRhdGEgaXMgc3RpbGwgc2tld2VkIGFuZCBhIHNsaWdodCBjdXJ2ZSBzdGlsbCBleGlzdHMsIHRoZSBkYXRhIGlzbid0IGFzIHNrZXdlZCBhcyBiZWZvcmUuIAoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KZ2dwbG90KGExX2RhdGEsIGFlcyh4ID0gbWVkaWFuX2luY29tZSwgeSA9IGxvZyhkaWFiZXRlc19wcmV2YWxlbmNlKSkpICsKICBnZW9tX3BvaW50KGNvbCA9ICJibGFjayIpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gInJlZCIsIHNlID0gRkFMU0UpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgY29sID0gImJsdWUiLCBzZSA9IEZBTFNFKSArIAogIGxhYnModGl0bGUgPSAiUmVsYXRpb25zaGlwIEJldHdlZW4gTWVkaWFuIEluY29tZSBhbmQgRGlhYmV0ZXMgUHJldmFsZW5jZSIsCiAgICAgICB4ID0gIk1lZGlhbiBJbmNvbWUgb2YgQ291bnR5IGluIFRob3VzYW5kcyBvZiBEb2xsYXJzIiwKICAgICAgIHkgPSAibG9nKERpYWJldGVzIFByZXZhbGVuY2UgUGVyY2VudGFnZSBvZiBDb3VudHkpIikKYGBgCgoKIyMgRml0dGVkIE1vZGVsCgpgYGB7cn0KYTFfbW9kZWwgPC0gbG0obG9nKGRpYWJldGVzX3ByZXZhbGVuY2UpIH4gbWVkaWFuX2luY29tZSwgZGF0YSA9IGExX2RhdGEpCgojIFJeMiwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucwpnbGFuY2UoYTFfbW9kZWwpIHw+IHNlbGVjdChyLnNxdWFyZWQsIHNpZ21hLCBub2JzKQoKIyBwZWFyc29uIGNvcnJlbGF0aW9uCmNvcihhMV9kYXRhJG1lZGlhbl9pbmNvbWUsIGExX2RhdGEkZGlhYmV0ZXNfcHJldmFsZW5jZSkKYGBgCgoKIyMjIFByZWRpY3Rpb24gRXF1YXRpb24KYGBge3J9CiMgY29lZmZpY2llbnRzCmV4dHJhY3RfZXEoYTFfbW9kZWwsIHVzZV9jb2VmcyA9IFRSVUUsIG9wZXJhdG9yX2xvY2F0aW9uID0gInN0YXJ0IiwKICAgICAgICAgICB3cmFwID0gVFJVRSwgY29lZl9kaWdpdHMgPSAyKQpgYGAKClRoZSBwcmVkaWN0aW9uIGVxdWF0aW9uIGlzIGxvZyhkaWFiZXRlc19wcmV2YWxlbmNlKSA9IDMuMDIgLSAwLjAxKG1lZGlhbl9pbmNvbWUpLiBUaGlzIG1lYW5zIHRoYXQgaWYgYSBjb3VudHkgaGFzIGEgbWVkaWFuIGluY29tZSBvZiAwLDAwMCBkb2xsYXJzLCB0aGVuIHRoZSBleHBlY3RlZCBsb2cgdmFsdWUgb2YgdGhlIGNvdW50eSdzIGRpYWJldGVzIHByZXZhbGVuY2UgcGVyY2VudGFnZSBpcyAzLjAyLiBJdCBhbHNvIG1lYW5zIHRoYXQgZm9yIGVhY2ggaW5jcmVhc2Ugb2YgMSwwMDAgZG9sbGFycyBvZiBhIGNvdW50eSdzIG1lZGlhbiBpbmNvbWUsIHRoZSBleHBlY3RlZCBsb2cgdmFsdWUgb2YgdGhlIGNvdW50eSdzIGRpYWJldGVzIHByZXZhbGVuY2UgcGVyY2VudGFnZSB3aWxsIGRlY3JlYXNlIGJ5IDAuMDEuCgojIyMgTW9kZWwgQ29lZmZpY2llbnRzCmBgYHtyfQp0aWR5KGExX21vZGVsLCBjb25mLmludCA9IFRSVUUsIGNvbmYubGV2ZWwgPSAwLjkwKSB8PiAKICBzZWxlY3QodGVybSwgZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpIHw+CiAga2JsKGRpZ2l0cyA9IDIpCmBgYAoKCiMjIyBTdW1tYXJpZXMgb2YgTW9kZWwgRml0CiAkUl4yJCAgIFJlc2lkdWFsIFN0YW5kYXJkIEVycm9yICAgTnVtYmVyIG9mIEZpdHRlZCBPYnNlcnZhdGlvbnMgICBQZWFyc29uIENvcnJlbGF0aW9uCi0tLS0tLS0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQogMC41ODUgICAgICAgICAgIDAuMTI4ICAgICAgICAgICAgICAgICAgICAgICAgICAzMTUgICAgICAgICAgICAgICAgICAgICAgLTAuNzQ2CgoKIyMgUmVzaWR1YWwgQW5hbHlzaXMKCiMjIyBSZXNpZHVhbCBQbG90cwpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQphMV9hdWcgPC0gYXVnbWVudChhMV9tb2RlbCwgbmV3ZGF0YSA9IGExX2RhdGEpCgpwMSA8LSBnZ3Bsb3QoYTFfYXVnLCBhZXMoeCA9IC5maXR0ZWQsIHkgPSAucmVzaWQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAicmVkIiwgc2UgPSBGQUxTRSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBjb2wgPSAiYmx1ZSIsIHNlID0gRkFMU0UpICsKICBsYWJzKHRpdGxlID0gIlJlc2lkdWFscyB2cy4gRml0dGVkIFZhbHVlcyIsIAogICAgICAgeCA9ICJGaXR0ZWQgbG9nKGRpYWJldGVzX3ByZXZhbGVuY2UpIFZhbHVlcyIsIHkgPSAiUmVzaWR1YWxzIikKCnAyIDwtIGdncGxvdChhMV9hdWcsIGFlcyhzYW1wbGUgPSAucmVzaWQpKSArCiAgZ2VvbV9xcShjb2wgPSAiYmxhY2siKSArIAogIGdlb21fcXFfbGluZShjb2wgPSAicmVkIikgKyAKICBsYWJzKHRpdGxlID0gIk5vcm1hbCBRLVE6IE1vZGVsIFJlc2lkdWFscyIpCgpwMSAvIHAyCmBgYAoKRnJvbSB0aGUgZmlyc3QgcGxvdCwgaXQgYXBwZWFycyB0aGF0IHRoZXJlIG1heSBiZSBzb21lIG5vbi1saW5lYXJpdHkgaW4gdGhlIHJlZ3Jlc3Npb24gcmVsYXRpb25zaGlwIGFzIHRoZXJlIGlzIGEgY3VydmUgaW4gdGhlIHJlc2lkdWFscyB2LiBmaXR0ZWQgdmFsdWVzIHBsb3QuIFRoaXMgbWVhbnMgdGhhdCB0aGUgbW9kZWwgZml0cyBzb21lIHBvaW50cyBiZXR0ZXIgdGhhbiBvdGhlcnMsIGFzIHRoZXJlIGlzbid0IGEgcmVsYXRpdmUgY29uc3RhbnQgcmVzaWR1YWwgdmFsdWUuIFRoZSB2YXJpYW5jZSBhY3Jvc3MgdGhlIGJvYXJkIGlzIGFsc28gcHJldHR5IGNvbnN0YW50LCB3aXRoIHRoZSBsZWZ0IHNpZGUgbG9va2luZyBhIGJpdCB1bmJhbGFuY2VkIHJlbGF0aXZlIHRvIHRoZSByaWdodCBzaWRlIGxpa2VseSBiZWNhdXNlIG9mIGl0cyBwb2ludCBzY2FyY2l0eS4gRnJvbSB0aGUgc2Vjb25kIHBsb3QsIGl0IGFwcGVhcnMgdGhhdCB0aGUgcmVzaWR1YWxzIGFyZSBwcmV0dHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYW5kIGhhcyBhIGNvdXBsZSBvZiBvdXRsaWVycyBvbiBlYWNoIGVuZCBvZiB0aGUgdmFsdWUgZXh0cmVtZXMuCgojIyMgQ3V5YWhvZ2EgQ291bnR5IENvbXBhcmlzb24KCmBgYHtyfQojIGdldCBpbmNvbWUgYW5kIGRpYWJldGVzIHZhbHVlcwpjdXlhaG9nYSA8LSBjaHJfMjAyMiB8PiBmaWx0ZXIoc3RhdGUgPT0gIk9IIikgfD4KICBmaWx0ZXIoY291bnR5ID09ICJDdXlhaG9nYSBDb3VudHkiKSB8PgogIHNlbGVjdChtZWRpYW5faW5jb21lLCBkaWFiZXRlc19wcmV2YWxlbmNlKQoKIyBwcmVkaWN0IHdpdGggbW9kZWwKY3V5YWhvZ2FfcHJlZGljdGlvbiA8LSBhdWdtZW50KGExX21vZGVsLCBuZXdkYXRhID0gY3V5YWhvZ2EpCiMgZ2V0IHVudHJhbnNmb3JtZWQgdmFsdWUgLT4gdW4tbG9nKCkKZml0dGVkX2RpYWJldGVzIDwtIGV4cChjdXlhaG9nYV9wcmVkaWN0aW9uJC5maXR0ZWQpCgpnbHVlKCJDdXlhaG9nYSBBY3R1YWw6IHtjdXlhaG9nYSRkaWFiZXRlc19wcmV2YWxlbmNlfSUKQ3V5YWhvZ2EgUHJlZGljdGVkOiB7cm91bmQoZml0dGVkX2RpYWJldGVzLCAyKX0lIikKYGBgCgojIyMgTGFyZ2VzdCBSZXNpZHVhbCBDb3VudGllcwoKYGBge3J9CiMgZ2V0IHByZWRpY3RlZCB2YWx1ZXMgZm9yIGFsbCBjb3VudGllcwpwbG90KGExX21vZGVsLCB3aGljaCA9IGMoMToyKSkKCiMgcHJpbnQgY291bnRpZXMgaW4gb3JkZXIgb2YgcmVzaWR1YWwgbWFnbml0dWRlCmluZGljZXMgPC0gYygxODAsIDczLCAxNzUpCmZvciAoaW5kZXggaW4gaW5kaWNlcykgewogICMgb3JpZ2luYWwgZGF0YQogIHByaW50KGNocl8yMDIyW2luZGV4LCBdIHw+IHNlbGVjdChjb3VudHksIHN0YXRlLCBtZWRpYW5faW5jb21lLCBkaWFiZXRlc19wcmV2YWxlbmNlKSkKICAjIHJlc2lkdWFsIHZhbHVlCiAgcHJpbnQoYTFfYXVnW2luZGV4LCBdIHw+IHNlbGVjdChtZWRpYW5faW5jb21lLCBkaWFiZXRlc19wcmV2YWxlbmNlLCAuZml0dGVkLCAucmVzaWQpKQp9CmBgYAoKVGhlIGNvdW50eSB3aXRoIHRoZSBsYXJnZXN0IGFic29sdXRlIHZhbHVlIHJlc2lkdWFsIGlzIEZyYW5rbGluIENvdW50eSwgTUEgKC0wLjM1NikuIEZvciB0aGUgc2Vjb25kIGxhcmdlc3QgYWJzb2x1dGUgdmFsdWUgcmVzaWR1YWwsIHRoZXJlIGFyZSB0d28gY291bnRpZXMgdGhhdCBhcmUgdGllZDogRm9yc3l0aCBDb3VudHksIEdBICgwLjMxNikgYW5kIEJhcm5zdGFibGUgQ291bnR5LCBNQSAoLTAuMzE2KS4KCiMjIENvbmNsdXNpb25zIGFuZCBMaW1pdGF0aW9ucwpUaGlzIGFuYWx5c2lzIHNlY3Rpb24gaW52ZXN0aWdhdGVkIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjb3VudGllcycgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgYW5kIHRoZWlyIGRpYWJldGVzIHByZXZhbGVuY2UgcGVyY2VudGFnZS4gQmFzZWQgb24gdGhlIGFuYWx5c2lzIHBlcmZvcm1lZCwgaXQgYXBwZWFycyBhcyBpZiB0aGVyZSBpcyBhIGRlY2VudGx5IG5lZ2F0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0d28gdmFyaWFibGVzLiBUaGlzIGNhbiBiZSBtb3N0IGNsZWFybHkgc2VlbiBieSB0aGUgcGVhcnNvbiBjb3JyZWxhdGlvbiBzY29yZSBvZiAtMC43NDYuIFRoZSByZXNpZHVhbCBzdGFuZGFyZCBlcnJvciB2YWx1ZXMgYWxzbyBwb2ludHMgdG8gdGhlIG1vZGVsIGJlaW5nIHByZXR0eSByZWxpYWJsZSBpbiBwcmVkaWN0aW5nIGNvdW50eSBkaWFiZXRlcyBwcmV2YWxlbmNlIHBlcmNlbnRhZ2VzLiBXaGVuIGNvbnZlcnRpbmcgdGhlIHJlc2lkdWFsIHN0YW5kYXJkIGVycm9yIG9mIDAuMTI4IGJhY2sgdG8gdGhlIG9yaWdpbmFsIHJhbmdlICgkZV57MC4xMjh9JCksIHRoZSB2YWx1ZSBpcyAxLjEzNy4gVGhpcyBpbmRpY2F0ZXMgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiByZXNpZHVhbHMsIHNvIGEgbG93IHNjb3JlIG9mIDEuMTM3IG1lYW5zIHRoYXQgdGhlIGZpdHRlZCB2YWx1ZXMgdGVuZCB0byBiZSBwcmV0dHkgY2xvc2UgdG8gdGhlIGFjdHVhbCBvbmVzLiBXaGlsZSB0aGVzZSBkZW1vbnN0cmF0ZSBhIHJlbGF0aXZlbHkgc3Ryb25nIGNvcnJlbGF0aW9uLCB0aGUgbW9kZWwncyAkUl4yJCBzY29yZSBvZiAwLjU4NSBzaG93cyB0aGF0IG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIG1heSBub3QgYmUgYSB2ZXJ5IGdvb2QgcHJlZGljdG9yIG9mIGRpYWJldGVzIHByZXZhbGVuY2UgdmFyaWFiaWxpdHkuIAoKQmFzZWQgb24gdGhlIGRhdGEgYW5hbHlzaXMsIHRoZXJlIGRvZXMgYXBwZWFyIHRvIGJlIHNvbWUgbGltaXRhdGlvbnMgdG8gb3VyIGNvbmNsdXNpb25zIGZyb20gYW5hbHlzaXMgMS4gVGhlIGZpcnN0IGxpbmVhciBtb2RlbCBhc3N1bXB0aW9uIG9mIGEgbGluZWFyIHJlbGF0aW9uc2hpcCBtYXkgbm90IGJlIGZ1bGx5IG1ldCBieSBvdXIgZGF0YSwgZXZlbiBvbmNlIGl0J3MgdHJhbnNmb3JtZWQuIFdoZW4gbG9va2luZyBhdCB0aGUgcmVzaWR1YWxzIHZlcnN1cyBmaXR0ZWQgdmFsdWVzIHBsb3QsIGEgc2xpZ2h0IGN1cnZlIGNhbiBiZSBzZWVuLiBUaGlzIG1lYW5zIHRoYXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG1lZGlhbiBpbmNvbWUgYW5kIGxvZyhkaWFiZXRlcyBwcmV2YWxlbmNlKSBtYXkgbm90IGJlIGZ1bGx5IGxpbmVhciwgc28gYSBsaW5lYXIgbW9kZWwgbWF5IG5vdCBiZSB0aGUgYmVzdCB3YXkgdG8gdXNlIG1lZGlhbiBpbmNvbWUgdG8gcHJlZGljdCBkaWFiZXRlcyBwcmV2YWxlbmNlLiBTb21lIG9mIHRoaXMgbWF5IGJlIGF0dHJpYnV0ZWQgdG8gb3V0bGllciB2YWx1ZXMgdGhvdWdoLCB3aGljaCBjYW4gYmUgc2VlbiBvbiB0aGUgbm9ybWFsIFFRIHBsb3Qgb2YgcmVzaWR1YWxzLiBNb3N0IG9mIHRoZSB2YWx1ZXMgc3RheSBhbG9uZyB0aGUgbm9ybWFsIGxpbmUsIGFsdGhvdWdoIGF0IGVhY2ggb2YgdGhlIGVuZHMsIHRoZXJlIGFyZSBzb21lIG91dGxpZXJzLiBXaGlsZSB0aGVyZSBhcmVuJ3QgdGhhdCBtYW55LCB0aGUgb3V0bGllcnMgbWF5IHNrZXcgdGhlIG1vZGVsIHJlc3VsdHMgYSBiaXQgaW4gb25lIHdheSBvciBhbm90aGVyLiBUaGVzZSBvdXRsaWVycyBtYXkgYWxzbyBiZSBkdWUgdG8gb3VyIGRhdGEncyBzZWxlY3Rpb24gb2Ygc3RhdGVzLCByZWdhcmRpbmcgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUuIFJlZ2FyZGluZyBtZWRpYW4gaW5jb21lLCBNYXNzYWNodXNldHRzIGFuZCBXYXNoaW5ndG9uIGFyZSBib3RoIGFtb25nIHRoZSB0b3AgNyBzdGF0ZXMgYW5kIGFyZSBwcmV0dHkgd2VsbCBhYm92ZSB0aGUgVVMgbWVkaWFuIGluY29tZSB3aGlsZSBPaGlvIGFuZCBHZW9yZ2lhIGFyZSBpbiB0aGUgYm90dG9tIDE1IHN0YXRlcyBhbmQgbm90aWNhYmx5IGxvd2VyIHRoYW4gdGhlIFVTIG1lZGlhbi4gVGhpcyBtZWFucyB0aGF0IHRoaXMgc3Vic2V0IG9mIHN0YXRlcyBtYXkgbm90IGJlIGJlc3Qgc3VpdGVkIHRvIGFjY3VyYXRlbHkgcmVwcmVzZW50IHRoZSBVUyB3aGVuIHJlbGF0aW5nIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIHRvIGRpYWJldGVzIHByZXZhbGVuY2UgcGVyY2VudGFnZS4KCgojIEFuYWx5c2lzIDIKCiMjIFZhcmlhYmxlcwoKRm9yIGFuYWx5c2lzIDIsIHdlIHdpbGwgYmUgdXNpbmcgdGhlIGxpbWl0ZWQgYWNjZXNzIHRvIGhlYWx0aHkgZm9vZCBjYXRlZ29yaWNhbCAgdmFyaWFibGUgKGxpbWl0ZWRfaGVhbHRoeV9jYXQpIGFzIHRoZSBwcmVkaWN0b3Igd2l0aCBhIGJhc2VsaW5lIGNhdGVnb3J5IG9mICdsb3dlc3QnIGFuZCBkaWFiZXRlcyBwcmV2YWxlbmNlIChkaWFiZXRlc19wcmV2YWxlbmNlKSBhcyB0aGUgb3V0Y29tZSB2YXJpYWJsZSBmcm9tIHRoZSBjaHJfMjAyMiB0aWJibGUuIGxpbWl0ZWRfaGVhbHRoeV9jYXQgcmVwcmVzZW50cyBhIGNhdGVnb3J5IHRoYXQgY29ycmVzcG9uZHMgdG8gYSBjb3VudHkncyBwZXJjZW50YWdlIG9mIGxpbWl0ZWQgYWNjZXNzIHRvIGhlYWx0aHkgZm9vZHMsIHNvIGluIGVzc2VuY2UgdGhlIHBlcmNlbnRhZ2Ugb2YgcmVzaWRlbnRzIHRoYXQgY2FuJ3QgZWFzaWx5IG9idGFpbiBoZWFsdGh5IGZvb2RzLiBXaXRoaW4gdGhlIHZhcmlhYmxlLCB0aGVyZSBhcmUgZml2ZSBjYXRlZ29yaWVzLCB3aGljaCB3ZXJlIGRpdmlkZWQgdXNpbmcgYSBtZXRob2QgdGhhdCBtYWRlIHN1cmUgZWFjaCBjYXRlZ29yeSBoYWQgYW4gZXF1YWwgbnVtYmVyIG9mIGNvdW50aWVzICgrLSAxKS4gVGhlIGRpYWJldGVzX3ByZXZhbGVuY2UgdmFyaWFibGUgbWVhc3VyZXMgdGhlIGRpYWJldGVzIHByZXZhbGVuY2UgcGVyY2VudGFnZSBvZiByZXNpZGVudHMgaW4gdGhlIGNvdW50eS4gVGhlIGNvdW50aWVzIGluIHRoZSBkYXRhIGNvbWUgZnJvbSBBcml6b25hLCBHZW9yZ2lhLCBNYXNzYWNodXNldHRzLCBPaGlvLCBhbmQgV2FzaGluZ3RvbiBhbmQgdGhlcmUgYXJlIDUgY291bnRpZXMgd2l0aCBtaXNzaW5nIGRhdGEgZm9yIHRoZSBwcmVkaWN0b3IgdmFyaWFibGUuIFdpdGggdGhpcywgd2UgYXJlIGdvaW5nIHRvIGRyb3AgdGhlc2UgY291bnRpZXMgYXMgbWFrZSBhIHZlcnkgc21hbGwgcGVyY2VudGFnZSAoMS41OSUpIG9mIHRoZSBlbnRpcmUgZGF0YXNldCBhbmQgdGhleSB3ZXJlIGFsc28gZXhjbHVkZWQgd2hlbiBzcGxpdHRpbmcgbGltaXRlZF9oZWFsdGh5X2NhdCBpbnRvIHZhcmlvdXMgY2F0ZWdvcmllcyBGb3IgQ3V5YWhvZ2EgQ291bnR5LCBPaGlvLCB0aGUgdmFsdWVzIG9mIHRoZSBwcmVkaWN0b3IgYW5kIG91dGNvbWUgdmFyaWFibGUgYXJlIGxpbWl0ZWRfaGVhbHRoeV9jYXQgPSAnbG93JyBhbmQgZGlhYmV0ZXNfcHJldmFsZW5jZSA9IDExLjEuCgpgYGB7cn0KIyBvbmx5IGdldCBsaW1pdGVkX2hlYWx0aHlfY2F0IGFuZCBkaWFiZXRlc19wcmV2YWxlbmNlCmEyX2RhdGEgPC0gY2hyXzIwMjIgfD4gCiAgc2VsZWN0KGxpbWl0ZWRfaGVhbHRoeV9jYXQsIGRpYWJldGVzX3ByZXZhbGVuY2UpIHw+IAogIGZpbHRlcihjb21wbGV0ZS5jYXNlcyhsaW1pdGVkX2hlYWx0aHlfY2F0LCBkaWFiZXRlc19wcmV2YWxlbmNlKSkKCmRpbShhMl9kYXRhKQoKIyBnZXQgdmFsdWVzIGZvciBDdXlhaG9nYSBDb3VudHkKY2hyXzIwMjIgfD4gZmlsdGVyKHN0YXRlID09ICJPSCIpIHw+CiAgZmlsdGVyKGNvdW50eSA9PSAiQ3V5YWhvZ2EgQ291bnR5IikgfD4KICBzZWxlY3QobGltaXRlZF9oZWFsdGh5X2NhdCwgZGlhYmV0ZXNfcHJldmFsZW5jZSkKYGBgCgojIyBSZXNlYXJjaCBRdWVzdGlvbgoKQXJlIHRoZXJlIHN0YXRpc3RpY2FsIHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGluIG1lYW4gdmFsdWVzIG9mIGRpYWJldGVzIHByZXZhbGVuY2UgZm9yIGVhY2ggcHJvZ3Jlc3NpdmUgbGV2ZWwgb2YgbGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcyAobG93ZXN0LWxvdywgbG93LW1pZGRsZSwgbWlkZGxlLWhpZ2gsIGhpZ2gtaGlnaGVzdCkgaW4gMzEwIGNvdW50aWVzIGFjcm9zcyB0aGUgc3RhdGVzIG9mIEFyaXpvbmEsIEdlb3JnaWEsIE1hc3NhY2h1c2V0dHMsIE9oaW8sIGFuZCBXYXNoaW5ndG9uPwoKIyMgRGF0YSBWaXN1YWxpemF0aW9uCgpgYGB7cn0KZ2dwbG90KGEyX2RhdGEsIGFlcyh4ID0gbGltaXRlZF9oZWFsdGh5X2NhdCwgeSA9IGRpYWJldGVzX3ByZXZhbGVuY2UpKSArCiAgZ2VvbV92aW9saW4oYWVzKGZpbGwgPSBsaW1pdGVkX2hlYWx0aHlfY2F0KSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjI1KSArIAogIGNvb3JkX2ZsaXAoKSArIAogIGxhYnModGl0bGUgPSAiRGlhYmV0ZXMgUHJldmFsZW5jZSBieSBMaW1pdGVkIEFjY2VzcyB0byBIZWFsdGh5IEZvb2RzIExldmVsIiwKICAgICAgIHggPSAiTGltaXRlZCBBY2Nlc3MgdG8gSGVhbHRoeSBGb29kcyBMZXZlbCIsCiAgICAgICB5ID0gIkRpYWJldGVzIFByZXZhbGVuY2UiKQoKbW9zYWljOjpmYXZzdGF0cyhkaWFiZXRlc19wcmV2YWxlbmNlIH4gbGltaXRlZF9oZWFsdGh5X2NhdCwgZGF0YSA9IGEyX2RhdGEpCmBgYAoKRm9yIGFuYWx5c2lzIDIsIHdlIHdpbGwgbm90IGJlIHRyYW5zZm9ybWluZyB0aGUgb3V0Y29tZSB2YXJpYWJsZSBhcyB0aGUgb3V0Y29tZSB2YXJpYWJsZSBpcyBwcmV0dHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIGEgZmV3IG91dGxpZXJzLiBGdXJ0aGVybW9yZSwgdGhlIGNhdGVnb3JpY2FsIHByZWRpY3RvciB2YXJpYWJsZSBoYXMgdmVyeSBzaW1pbGFyIHZhcmlhbmNlIGFjcm9zcyBhbGwgY2F0ZWdvcnkgbGV2ZWxzLiBGcm9tIHRoZSBib3hwbG90IHdpdGggdmlvbGluIHBsb3RzLCBpdCBhcHBlYXJzIHRoYXQgYWxsIG9mIHRoZSBwcmVkaWN0b3IgdmFyaWFibGUgbGV2ZWxzIGhhdmUgYSBzaW1pbGFyIHJhbmdlIG9mIHZhbHVlcy4gSXQgY2FuIGFsc28gYmUgc2VlbiB0aGF0IHRoZSBsZXZlbHMgYXJlIGFsbCByZWxhdGl2ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBhbGJlaXQgd2l0aCB2YXJpb3VzIGxldmVscyBvZiBwZWFrIHZhbHVlcy4gTm9uZSBvZiB0aGUgbGV2ZWxzIGFwcGVhciB0byBiZSBuZWFyIGlkZW50aWNhbCwgaW4gYW55IHNlbnNlLCBidXQgb25lIGludGVyZXN0aW5nIHRoaW5nIHRvIGxvb2sgYXQgaXMgdGhlIG1lZGlhbiB2YWx1ZXMgb2YgZWFjaCBjYXRlZ29yeSBsZXZlbC4gRXhjbHVkaW5nIHRoZSAnbG93ZXN0JyBsZXZlbCwgdGhlIG1lZGlhbiB2YWx1ZSBvZiBkaWFiZXRlcyBwcmV2YWxlbmNlIG9mIGVhY2ggbGV2ZWwgaW5jcmVhc2VzIHdpdGhpbiBlYWNoIGxldmVsLCB3aGljaCBtYXkgaW5kaWNhdGUgdGhhdCB3aXRoIGhpZ2hlciBsZXZlbHMgb2YgbGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcywgdGhlcmUgYXJlIGhpZ2hlciBsZXZlbHMgb2YgZGlhYmV0ZXMgcHJldmFsZW5jZS4KCiMjIEZpdHRlZCBNb2RlbAoKYGBge3J9CmEyX21vZGVsIDwtIGxtKGRpYWJldGVzX3ByZXZhbGVuY2UgfiBsaW1pdGVkX2hlYWx0aHlfY2F0LCBkYXRhID0gYTJfZGF0YSkKYGBgCgoKIyMjIFByZWRpY3Rpb24gRXF1YXRpb24KYGBge3J9CiMgY29lZmZpY2llbnRzCmV4dHJhY3RfZXEoYTJfbW9kZWwsIHVzZV9jb2VmcyA9IFRSVUUsIG9wZXJhdG9yX2xvY2F0aW9uID0gInN0YXJ0IiwKICAgICAgICAgICB3cmFwID0gVFJVRSwgY29lZl9kaWdpdHMgPSAyLCB0ZXJtc19wZXJfbGluZSA9IDEpCmBgYAoKVGhlIHByZWRpY3Rpb24gZXF1YXRpb24gaXMgZGlhYmV0ZXNfcHJldmFsZW5jZSA9IDEyLjI5IC0gMS41MyhsaW1pdGVkX2hlYWx0aHlfY2F0JF97bG93fSQpIC0gMS4yMShsaW1pdGVkX2hlYWx0aHlfY2F0JF97bWlkZGxlfSQpIC0gMC44NShsaW1pdGVkX2hlYWx0aHlfY2F0JF97aGlnaH0kKSArIDAuODAobGltaXRlZF9oZWFsdGh5X2NhdCRfe2hpZ2hlc3R9JCkuIFRoaXMgbWVhbnMgdGhhdCBhIGNvdW50eSdzIHByZWRpY3RlZCBkaWFiZXRlcyBwcmV2YWxlbmNlIGlzIGRlcGVuZGVudCBvbiB0aGVpciBsaW1pdGVkIGFjY2VzcyB0byBoZWFsdGh5IGZvb2RzIGNhdGVnb3JpY2FsIGxldmVsLiBJZiB0aGVpciBsZXZlbCBpcyBsb3dlc3QsIHRoZW4gdGhlIGV4cGVjdGVkIGRpYWJldGVzIHByZXZhbGVuY2UgaXMgMTIuMjkuIFNpbmNlIGVhY2ggY291bnR5IGNhbiBvbmx5IGJlIGluIG9uZSBjYXRlZ29yeSBsZXZlbCwgdGhlbiBhdCBtb3N0IG9ubHkgb25lIG9mIHRoZSBjb2VmZmljaWVudHMgd2lsbCBiZSB1c2VkLiBJZiB0aGVpciBsZXZlbCBpcyBsb3dlc3QsIHRoZW4gaXQncyBleHBlY3RlZCB0aGF0IHRoZWlyIGRpYWJldGVzIHByZXZhbGVuY2Ugd2lsbCBiZSB0aGUgaW50ZXJjZXB0IHZhbHVlICgxMi4yOSkuIElmIHRoZWlyIGxldmVsIGlzIGxvdywgdGhlbiBpdCdzIGV4cGVjdGVkIHRoYXQgdGhlaXIgZGlhYmV0ZXMgcHJldmFsZW5jZSB3aWxsIGRlY3JlYXNlIGJ5IDEuNTMgdG8gMTAuNzYuIElmIHRoZWlyIGxldmVsIGlzIG1pZGRsZSwgdGhlbiBpdCdzIGV4cGVjdGVkIHRoYXQgdGhlaXIgZGlhYmV0ZXMgcHJldmFsZW5jZSB3aWxsIGRlY3JlYXNlIGJ5IDEuMjEgdG8gMTEuMDguIElmIHRoZWlyIGxldmVsIGlzIGhpZ2gsIHRoZW4gaXQncyBleHBlY3RlZCB0aGF0IHRoZWlyIGRpYWJldGVzIHByZXZhbGVuY2Ugd2lsbCBkZWNyZWFzZSBieSAwLjg1IHRvIDExLjQ0LiBJZiB0aGVpciBsZXZlbCBpcyBoaWdoZXN0LCB0aGVuIGl0J3MgZXhwZWN0ZWQgdGhhdCB0aGVpciBkaWFiZXRlcyBwcmV2YWxlbmNlIHdpbGwgaW5jcmVhc2UgYnkgMC44MCB0byAxMy4wOS4KCiMjIyBNb2RlbCBDb2VmZmljaWVudHMKCmBgYHtyfQp0aWR5KGEyX21vZGVsLCBjb25mLmludCA9IFRSVUUsIGNvbmYubGV2ZWwgPSAwLjkwKSB8PiAKICBzZWxlY3QodGVybSwgZXN0aW1hdGUsIGNvbmYubG93LCBjb25mLmhpZ2gpIHw+CiAga2JsKGRpZ2l0cyA9IDIpCmBgYAoKIyMjIFN1bW1hcmllcyBvZiBNb2RlbCBGaXQKYGBge3J9CnRpZHkoYW5vdmEoYTJfbW9kZWwpKSB8PiBrYmwoZGlnaXRzID0gMykgfD4ga2FibGVfY2xhc3NpY18yKCkKCmdsYW5jZShhMl9tb2RlbCkgfD4gc2VsZWN0KHIuc3F1YXJlZCwgc2lnbWEsIG5vYnMpCmBgYAoKICRSXjIkICAgUmVzaWR1YWwgU3RhbmRhcmQgRXJyb3IgICBOdW1iZXIgb2YgRml0dGVkIE9ic2VydmF0aW9ucwotLS0tLS0tIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogMC4xMzIgICAgICAgICAgIDIuMTkgICAgICAgICAgICAgICAgICAgICAgICAgIDMxMAogCiAKRnJvbSB0aGUgQW5vdmEgdGFibGUsIHdlIGNhbiBzZWUgdGhhdCB3ZSBjYW4gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgc2luY2UgdGhlIHAtdmFsdWUgaXMgc21hbGxlciB0aGFuIDAuMTAgKGNhbid0IHNlZSBiZWNhdXNlIG9mIGRpZ2l0cyBidXQgdmFsdWUgaXMgOC40MzNlLTA5KS4gVGhpcyBtZWFucyB0aGF0IGF0IGxlYXN0IG9uZSBvZiB0aGUgbWVhbiB2YWx1ZXMgb2YgdGhlIGNhdGVnb3J5IGdyb3VwcyBpcyBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCB0aGFuIHRoZSBvdGhlcnMuIFNpbmNlIHdlIGNhbiBjb25jbHVkZSB0aGF0IGEgY291bnR5J3MgbGV2ZWwgb2YgbGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcyBwcm92aWRlcyBtZWFuaW5nZnVsIHByZWRpY3RpdmUgdmFsdWUgYXMgdG8gdGhlIG1lYW5zJyBvZiBlYWNoIGdyb3VwLCB3ZSB3aWxsIHBlcmZvcm0gVHVrZXkncyBIb25lc3RseSBTaWduaWZpY2FudCBEaWZmZXJlbmNlcyB0ZXN0IHRvIHNlZSBpZiB0aGVyZSBhcmUgc3RhdGlzdGljYWxseSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBtZWFuJ3Mgb2YgZWFjaCBncm91cCB2ZXJzdXMgYWxsIHRoZSBvdGhlciBncm91cHMuCgpgYGB7cn0KVHVrZXlIU0QoYW92KGxtKGRpYWJldGVzX3ByZXZhbGVuY2UgfiBsaW1pdGVkX2hlYWx0aHlfY2F0LCBkYXRhID0gYTJfZGF0YSkpLCAKICAgICAgICAgY29uZi5sZXZlbCA9IDAuOTAsIG9yZGVyZWQgPSBGQUxTRSkKYGBgCgpCeSBydW5uaW5nIFR1a2V5J3MgSG9uZXN0bHkgU2lnbmlmaWNhbnQgRGlmZmVyZW5jZXMgdGVzdCwgd2UgY2FuIGRldGVybWluZSB3aGljaCBzcGVjaWZpYyBncm91cHMgb2YgbGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcyBoYXZlIHN0YXRpc3RpY2FsbHkgZGlmZmVyZW50IG1lYW5zLiBVc2luZyBhIDkwJSBjb25maWRlbmNlIGludGVydmFsIGFnYWluICgkXGFscGhhJCA9IDAuMTApLCB3ZSBjYW4gc2VlIHRoYXQgNSBwYWlycyBvZiBncm91cHMgaGF2ZSBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCBkaWFiZXRlcyBwcmV2YWxlbmNlIG1lYW4ncy4gVGhvc2UgZ3JvdXBzIHdvdWxkIGJlIGxvdy1sb3dlc3QgKDAuMDAxKSwgbWlkZGxlLWxvd2VzdCAoMC4wMjApLCBoaWdoZXN0LWxvdyAoMC4wMDApLCBoaWdoZXN0LW1pZGRsZSAoMC4wMDApLCBhbmQgaGlnaGVzdC1oaWdoICgwLjAwMCkuCgoKIyMgUHJlZGljdGlvbiBBbmFseXNpcwoKIyMjIFJlc2lkdWFsIFBsb3QKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KYTJfYXVnIDwtIGF1Z21lbnQoYTJfbW9kZWwsIG5ld2RhdGEgPSBhMl9kYXRhKQoKcDEgPC0gZ2dwbG90KGEyX2F1ZywgYWVzKHggPSAuZml0dGVkLCB5ID0gLnJlc2lkLCBjb2xvciA9IGxpbWl0ZWRfaGVhbHRoeV9jYXQpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gInJlZCIsIHNlID0gRkFMU0UpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgY29sID0gImJsdWUiLCBzZSA9IEZBTFNFKSArIAogIGxhYnModGl0bGUgPSAiUmVzaWR1YWxzIHZzLiBGaXR0ZWQgVmFsdWVzIiwgCiAgICAgICB4ID0gIkZpdHRlZCBkaWFiZXRlc19wcmV2YWxlbmNlIFZhbHVlcyIsIHkgPSAiUmVzaWR1YWwgVmFsdWVzIikKCnAyIDwtIGdncGxvdChhMl9hdWcsIGFlcyhzYW1wbGUgPSAucmVzaWQpKSArCiAgZ2VvbV9xcSgpICsgCiAgZ2VvbV9xcV9saW5lKGNvbCA9ICJyZWQiKSArIAogIGxhYnModGl0bGUgPSAiUmVzaWR1YWwgUVEgUGxvdCIsCiAgICAgICB5ID0gIiIpCgpwMyA8LSBnZ3Bsb3QoYTJfYXVnLCBhZXMoeCA9IC5yZXNpZCwgeSA9ICIiKSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSAiZG9kZ2VyIGJsdWUiKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4yNSkgKyAKICBsYWJzKHRpdGxlID0gIlJlc2lkdWFsIFZhbHVlIEhpc3RvZ3JhbSIsCiAgICAgICB5ID0gIiIsIAogICAgICAgeCA9ICIiKQoKIyBkaWRuJ3QgcGF0Y2ggdGhlbSB0b2dldGhlciBhcyBwbG90cyBkaWRuJ3QgbG9vayBnb29kIHNxdWVlemVkIGluIGFueSB3YXkKcDEKcDIKcDMKYGBgCgpGcm9tIHRoZSBmaXJzdCB0d28gcGxvdHMsIGl0IGFwcGVhcnMgdGhhdCB0aGUgcmVncmVzc2lvbiByZWxhdGlvbnNoaXAgYmV0d2VlbiBsZXZlbCBvZiBsaW1pdGVkIGFjY2VzcyB0byBoZWFsdGh5IGZvb2RzIGFuZCBkaWFiZXRlcyBwcmV2YWxlbmNlIGZpdHMgcHJldHR5IHdlbGwuIFRoZSBmaXJzdCBwbG90IG1ha2VzIGl0IGxvb2sgbGluZWFyIGFzIHRoZSBsaW5lIG9mIGJlc3QgZml0IGhhcyBubyBjdXJ2ZS4gSW4gZ2VuZXJhbCwgYWxsIGNhdGVnb3J5IGxldmVscyBzZWVtIHRvIGhhdmUgcmVsYXRpdmVseSBzaW1pbGFyIHZhcmlhbmNlIHdoZW4gbm90IGNvbnNpZGVyaW5nIG91dGxpZXJzLCB3aGljaCBjYW4gYmUgc2VlbiB3aGVuIGxvb2tpbmcgYXQgZWFjaCBncm91cCBpbmRpdmlkdWFsbHkgaW4gcGxvdCAyLiBUaGUgcmVncmVzc2lvbiByZXNpZHVhbHMgbG9vayBwcmV0dHkgbm9ybWFsIGluIHRoZSBRUSBwbG90IGFzIG1vc3QgcG9pbnRzIGFyZSBhbG9uZyB0aGUgbm9ybWFsIFFRIGxpbmUuIEhvd2V2ZXIsIGl0IGFwcGVhcnMgdG8gaGF2ZSBhIHNsaWdodCB1cHdhcmQgY3VydmUsIHdoaWNoIGluZGljYXRlcyBhIHJpZ2h0IHNrZXcuIFRoaXMgaXMgcmVpbmZvcmNlZCBpbiB0aGUgdGhpcmQgcGxvdCwgYXMgdGhlIG1lZGlhbiBpcyBzbGlnaHRseSBzaGlmdGVkIGxlZnQgYW5kIHRoZXJlIGlzIGEgc2xpZ2h0bHkgbG9uZ2VyIHJpZ2h0IHRhaWwuIAoKIyMjIFByZWRpY3Rpb24gZm9yIEN1eWFob2dhIENvdW50eSwgT0gKCmBgYHtyfQojIGdldCBsaW1pdGVkIGFjY2VzcyB0byBoZWFsdGh5IGZvb2RzIGNhdGVnb3J5IGFuZCBkaWFiZXRlcyB2YWx1ZQpjdXlhaG9nYSA8LSBjaHJfMjAyMiB8PiBmaWx0ZXIoc3RhdGUgPT0gIk9IIikgfD4KICBmaWx0ZXIoY291bnR5ID09ICJDdXlhaG9nYSBDb3VudHkiKSB8PgogIHNlbGVjdChsaW1pdGVkX2hlYWx0aHlfY2F0LCBkaWFiZXRlc19wcmV2YWxlbmNlKQoKIyBwcmVkaWN0IHdpdGggbW9kZWwKY3V5YWhvZ2FfcHJlZGljdGlvbiA8LSBhdWdtZW50KGEyX21vZGVsLCBuZXdkYXRhID0gY3V5YWhvZ2EpCmZpdHRlZF9kaWFiZXRlcyA8LSBjdXlhaG9nYV9wcmVkaWN0aW9uJC5maXR0ZWQKCmdsdWUoIkN1eWFob2dhIEFjdHVhbDoge2N1eWFob2dhJGRpYWJldGVzX3ByZXZhbGVuY2V9JQpDdXlhaG9nYSBQcmVkaWN0ZWQ6IHtyb3VuZChmaXR0ZWRfZGlhYmV0ZXMsIDIpfSUiKQpgYGAKCiMjIyBUd28gTGVhc3QgU3VjY2Vzc2Z1bGx5IEZpdCBDb3VudGllcwoKYGBge3J9CiMgZ2V0IHByZWRpY3RlZCB2YWx1ZXMgZm9yIGFsbCBjb3VudGllcwpwbG90KGEyX21vZGVsLCB3aGljaCA9IGMoMToyKSkKCiMgcHJpbnQgY291bnRpZXMgaW4gb3JkZXIgb2YgcmVzaWR1YWwgbWFnbml0dWRlCmluZGljZXMgPC0gYygxNDAsIDM0KQpmb3IgKGluZGV4IGluIGluZGljZXMpIHsKICAjIG9yaWdpbmFsIGRhdGEKICBjb21wbGV0ZXMgPC0gY2hyXzIwMjIgfD4gZmlsdGVyKGNvbXBsZXRlLmNhc2VzKGNocl8yMDIyKSkKICBwcmludChjb21wbGV0ZXNbaW5kZXgsIF0gfD4gc2VsZWN0KGNvdW50eSwgc3RhdGUsIGxpbWl0ZWRfaGVhbHRoeV9jYXQsIGRpYWJldGVzX3ByZXZhbGVuY2UpKQogICMgcmVzaWR1YWwgdmFsdWUKICBwcmludChhMl9hdWdbaW5kZXgsIF0gfD4gc2VsZWN0KGxpbWl0ZWRfaGVhbHRoeV9jYXQsIGRpYWJldGVzX3ByZXZhbGVuY2UsIC5maXR0ZWQsIC5yZXNpZCkpCn0KYGBgCgpUaGUgY291bnR5IHdpdGggdGhlIGxhcmdlc3QgYWJzb2x1dGUgdmFsdWUgcmVzaWR1YWwgaXMgU3Rld2FydCBDb3VudHksIEdBICg3LjI2MCkgYW5kIHRoZSBjb3VudHkgd2l0aCB0aGUgc2Vjb25kIGxhcmdlc3QgYWJzb2x1dGUgdmFsdWUgcmVzaWR1YWwgaXMgQ2FsaG91biBDb3VudHksIEdBICg3LjIxOCkuCgojIyBDb25jbHVzaW9ucyBhbmQgTGltaXRhdGlvbnMKCkluIHRoZSBzZWNvbmQgYW5hbHlzaXMsIHdlIHdhbnRlZCB0byBzZWUgaWYgdGhlcmUgd2VyZSBzdGF0aXN0aWNhbCBkaWZmZXJlbmNlcyBpbiBtZWFuIHZhbHVlcyBvZiBkaWFiZXRlcyBwcmV2YWxlbmNlIGZvciBlYWNoIHByb2dyZXNzaXZlIGxldmVsIG9mIGxpbWl0ZWQgYWNjZXNzIHRvIGhlYWx0aHkgZm9vZHMuIEFmdGVyIHJ1bm5pbmcgYW4gQU5PVkEgdGVzdCBhbmQgdGhlbiBUdWtleSdzIGhvbmVzdGx5IHNpZ25pZmljYW50IGRpZmZlcmVuY2UgdGVzdCwgaXQgd2FzIGZvdW5kIHRoYXQgbm90IGFsbCBvZiB0aGUgcHJvZ3Jlc3NpdmUgZ3JvdXBzIGhhZCBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCBtZWFucy4gVGhlcmUgd2VyZSBmaXZlIHBhaXJzIHRoYXQgd2VyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCB3aGljaCB3ZXJlIGxvdy1sb3dlc3QsIG1pZGRsZS1sb3dlc3QsIGhpZ2hlc3QtbG93LCBoaWdoZXN0LW1pZGRsZSwgYW5kIGhpZ2hlc3QtaGlnaC4gV2l0aCB0aGF0LCB0aGUgb25seSBwcm9ncmVzc2l2ZSBncm91cHMgd2VyZSBsb3dlc3QtbG93IGFuZCBoaWdoLWhpZ2hlc3QuIFNvbWV0aGluZyBpbnRlcmVzdGluZyB0byBub3RlIGlzIHRoYXQgZWFjaCBvZiB0aGUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBwYWlycyBpbmNsdWRlZCBlaXRoZXIgdGhlIGxvd2VzdCBvciBoaWdoZXN0IGxpbWl0ZWQgYWNjZXNzIHRvIGhlYWx0aHkgZm9vZHMgZ3JvdXAuIFRoaXMgbWF5IGluZGljYXRlIHRoYXQgdGhvc2Ugd2VyZSB0aGUgb25seSB0d28gdGhhdCB3ZXJlIHZlcnkgZGlmZmVyZW50IHRoYW4gdGhlIG90aGVyIHRocmVlIChsb3csIG1pZGRsZSwgaGlnaCkuCgpGcm9tIG91ciBhbmFseXNpcywgaXQgZG9lc24ndCBhcHBlYXIgdGhhdCB0aGVyZSBhcmUgdmVyeSBtYW55IGxpbWl0YXRpb25zIHRvIG91ciBjb25jbHVzaW9ucywgCnNvIG91ciBjb25jbHVzaW9ucyBhcmUgbGlrZWx5IHByZXR0eSBzb2xpZC4gT25lIHRoaW5nIHRvIG5vdGUgaXMgdGhhdCBmb3IgdGhlIG1pZGRsZSBhbmQgaGlnaCBncm91cHMgb2YgbGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcywgdGhlcmUgYXJlIGEgY291cGxlIG9mIHJlbGF0aXZlbHkgZXh0cmVtZSBvdXRsaWVycy4gU29tZXRoaW5nIHRoYXQgbWF5IGJlIGFuIGlzc3VlIGlzIHRoYXQgdGhlcmUgd2FzIGEgcmlnaHQgc2tldyBpbiB0aGUgcmVzaWR1YWxzLCB0ZWxsaW5nIHRoYXQgdGhlcmUgYXJlIG1vcmUgbmVnYXRpdmUgcmVzaWR1YWwgdmFsdWVzIHRoYW4gcG9zaXRpdmUgb25lcy4gVGhlIGRpc3RyaWJ1dGlvbiBpcyBzdGlsbCBub3JtYWwgdGhvdWdoIHdpdGggYSBjb3VwbGUgb2Ygb3V0bGllcnMsIHdoaWNoIGlzIGEgZ29vZCBzaWduIHdoZW4gcnVubmluZyBhIGxpbmVhciBtb2RlbC4gQW5vdGhlciBsaW1pdGF0aW9uIGlzIHdpdGggdGhlIG1ldGhvZCB1c2VkIHRvIGRpdmlkZSBjb3VudGllcyB1cCBpbnRvIHZhcmlvdXMgbGltaXRlZCBhY2Nlc3MgdG8gaGVhbHRoeSBmb29kcyBsZXZlbHMuIFRvIGVuc3VyZSB0aGF0IGVhY2ggbGV2ZWwgaGFkIGVub3VnaCBjb3VudGllcywgd2UgdXNlZCBhIG1ldGhvZCB0aGF0IHNpbXBseSBtYWRlIGl0IHNvIGVhY2ggbGV2ZWwgaGFkIHRoZSBzYW1lIGFtb3VudCBvZiBjb3VudGllcy4gQmVjYXVzZSBvZiB0aGF0LCB0aGUgcmFuZ2VzIG9mIGVhY2ggbGV2ZWwgaXMgbm90IHRoZSBzYW1lIGFuZCBzb21lIGFyZSBtdWNoIGxhcmdlciB0aGFuIG90aGVycywgc28gdGhlIGxldmVscyBhcmUgbW9yZSByZXByZXNlbmF0aXZlIGFuZCByZWxhdGl2ZSB0byB0aGlzIGRhdGEncyBzdWJzZXQgb2YgVVMgY291bnRpZXMgdGhhbiB0aGUgcG9wdWxhdGlvbiBhcyBhIHdob2xlLgoKCiMgQW5hbHlzaXMgMwoKIyMgVmFyaWFibGVzCgpXZSB3aWxsIGJlIHVzaW5nIG1lZGlhbiBpbmNvbWUgYW5kIHN0YXRlIGFzIHByZWRpY3RvciB2YXJpYWJsZXMgYW5kIGRpYWJldGVzIHByZXZhbGVuY2UgYXMgdGhlIG91dGNvbWUgdmFyaWFibGUuIFRoZSBtZWRpYW4gaW5jb21lIHZhcmlhYmxlIG1lYXN1cmVzIHRoZSBjb3VudHkncyByZXNpZGVudHMnIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGluIHRob3VzYW5kcyBvZiBkb2xsYXJzLCB0aGUgc3RhdGUgdmFyaWFibGUgZXhwbGFpbnMgd2hhdCBzdGF0ZSB0aGUgY291bnR5IGlzIGluLCBhbmQgdGhlIGRpYWJldGVzIHByZXZhbGVuY2UgdmFyaWFibGUgbWVhc3VyZXMgdGhlIGRpYWJldGVzIHByZXZhbGVuY2UgcGVyY2VudGFnZSBvZiByZXNpZGVudHMgaW4gdGhlIGNvdW50eS4gRnJvbSBvdXIgdGliYmxlIChjaHJfMjAyMiksIHRoZSB2YXJpYWJsZXMgYXJlIGxpc3RlZCBhcyBtZWRpYW5faW5jb21lIChwcmVkaWN0b3IpLCBzdGF0ZSAocHJlZGljdG9yKSwgYW5kIGRpYWJldGVzX3ByZXZhbGVuY2UgKG91dGNvbWUpIGFjcm9zcyB0aGUgc3RhdGVzIG9mIEFyaXpvbmEsIEdlb3JnaWEsIE1hc3NhY2h1c2V0dHMsIE9oaW8sIGFuZCBXYXNoaW5ndG9uLCBhbmQgZWFjaCB2YXJpYWJsZSBoYXMgMzE1IGNvdW50aWVzIHdpdGggY29tcGxldGUgZGF0YS4gVGhlIHN0YXRlIHZhcmlhYmxlIGlzIGNvbnNpZGVyZWQgYW4gaW50ZXJhY3Rpb24gdGVybSwgYXMgdGhlIGludGVyY2VwdCBhbmQgc2xvcGUgb2YgdGhlIGVxdWF0aW9uIHdpbGwgYmUgaW1wYWN0ZWQgYnkgdGhlIGNvdW50eSdzIHN0YXRlLiBGb3IgQ3V5YWhvZ2EgQ291bnR5LCBPaGlvLCB0aGUgdmFsdWVzIG9mIHRoZSBwcmVkaWN0b3IgYW5kIG91dGNvbWUgdmFyaWFibGVzIGFyZSBzdGF0ZSA9ICJPSCIsIG1lZGlhbl9pbmNvbWUgPSA1NS4xMjgsIGFuZCBkaWFiZXRlc19wcmV2YWxlbmNlID0gMTEuMS4KCmBgYHtyfQojIGdldCBzdGF0ZSwgbWVkaWFuX2luY29tZSwgYW5kIGRpYWJldGVzX3ByZXZhbGVuY2UKYTNfZGF0YSA8LSBjaHJfMjAyMiB8PiAKICBzZWxlY3Qoc3RhdGUsIG1lZGlhbl9pbmNvbWUsIGRpYWJldGVzX3ByZXZhbGVuY2UpIHw+IAogIGZpbHRlcihjb21wbGV0ZS5jYXNlcyhtZWRpYW5faW5jb21lLCBkaWFiZXRlc19wcmV2YWxlbmNlKSkKCmRpbShhM19kYXRhKQoKIyBnZXQgdmFsdWVzIGZvciBDdXlhaG9nYSBDb3VudHkKY2hyXzIwMjIgfD4gZmlsdGVyKHN0YXRlID09ICJPSCIpIHw+CiAgZmlsdGVyKGNvdW50eSA9PSAiQ3V5YWhvZ2EgQ291bnR5IikgfD4KICBzZWxlY3Qoc3RhdGUsIG1lZGlhbl9pbmNvbWUsIGRpYWJldGVzX3ByZXZhbGVuY2UpCmBgYAoKIyMgUmVzZWFyY2ggUXVlc3Rpb24KCkRvZXMgYSBjb3VudHkncyBzdGF0ZSBoZWxwIG1ha2UgdGhlaXIgbWVkaWFuIGluY29tZSBhIGJldHRlciBwcmVkaWN0b3IgKGJldHRlciB0aGFuIG1vZGVsIDEpIG9mIHRoZSBjb3VudHkncyBkaWFiZXRlcyBwcmV2YWxlbmNlIGluIDMxNSBjb3VudGllcyBhY3Jvc3MgdGhlIHN0YXRlcyBvZiBBcml6b25hLCBHZW9yZ2lhLCBNYXNzYWNodXNldHRzLCBPaGlvLCBhbmQgV2FzaGluZ3Rvbj8KCiMjIERhdGEgVmlzdWFsaXphdGlvbgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KZ2dwbG90KGEzX2RhdGEsIGFlcyh4ID0gbWVkaWFuX2luY29tZSwgeSA9IGRpYWJldGVzX3ByZXZhbGVuY2UpKSArCiAgZ2VvbV9wb2ludChjb2wgPSAiYmxhY2siKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJyZWQiLCBzZSA9IEZBTFNFKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGNvbCA9ICJibHVlIiwgc2UgPSBGQUxTRSkgKyAKICBmYWNldF9ncmlkKHN0YXRlIH4gLiwgbGFiZWxsZXIgPSAibGFiZWxfYm90aCIpICsKICBndWlkZXMoZmlsbCA9ICJub25lIikgKyAKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBCZXR3ZWVuIE1lZGlhbiBJbmNvbWUgYW5kIERpYWJldGVzIFByZXZhbGVuY2UgYnkgU3RhdGUiLAogICAgICAgeCA9ICJNZWRpYW4gSW5jb21lIG9mIENvdW50eSBpbiBUaG91c2FuZHMgb2YgRG9sbGFycyIsCiAgICAgICB5ID0gIkRpYWJldGVzIFByZXZhbGVuY2UgUGVyY2VudGFnZSBvZiBDb3VudHkiKQpgYGAKRnJvbSB0aGlzIHBsb3QsIGl0IGFwcGVhcnMgdGhhdCBlYWNoIGluZGl2aWR1YWwgc3RhdGUncyByZWxhdGlvbnNoaXAgYmV0d2VlbiBtZWRpYW4gaW5jb21lIGFuZCBkaWFiZXRlcyBwcmV2YWxlbmNlIGlzIG5lZ2F0aXZlLiBUaGUgIHNsb3BlJ3MgbmVnYXRpdmUgZGVncmVlIHZhcmllcyBieSBzdGF0ZSwgYWxvbmcgd2l0aCB0aGUgYW1vdW50IG9mIGRhdGEgcG9pbnRzLiBHZW9yZ2lhIGFuZCBPaGlvIGhhdmUgdGhlIG1vc3QgYW1vdW50IG9mIGNvdW50aWVzLCB3aGljaCBtZWFucyB0aGF0IHRoZXkgaGF2ZSBtYW55IG1vcmUgZGF0YSBwb2ludHMgdGhhbiBzdGF0ZXMgbGlrZSBBcml6b25hIGFuZCBNYXNzYWNodXNldHRzLiBXaXRoIHRoYXQsIEdlb3JnaWEgYW5kIE9oaW8gYWxzbyBoYXZlIGEgbGFyZ2VyIHJhbmdlIG9mIHZhbHVlcyBmb3IgYm90aCBtZWRpYW4gaW5jb21lIGFuZCBkaWFiZXRlcyBwcmV2YWxlbmNlLiBJdCBjYW4gYWxzbyBiZSBzZWVuIHRoYXQgTWFzc2FjaHVzZXR0cyBoYXMgYSBoaWdoZXIgcmFuZ2Ugb2YgbWVkaWFuIGluY29tZSB3aGlsZSBBcml6b25hIGlzIG9uIHRoZSBsb3dlciByYW5nZS4gCgojIyBGaXR0ZWQgTW9kZWwKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9CiMgbWFrZSBPaGlvIGJhc2VsaW5lCmEzX2RhdGEgPC0gYTNfZGF0YSB8PiBtdXRhdGUoc3RhdGUgPSBmY3RfcmVsZXZlbChzdGF0ZSwgIk9IIikpCgojIGNyZWF0ZSBtb2RlbAphM19tb2RlbCA8LSBsbShkaWFiZXRlc19wcmV2YWxlbmNlIH4gbWVkaWFuX2luY29tZSAqIHN0YXRlLCBkYXRhID0gYTNfZGF0YSkKCiMgUl4yLCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zCmdsYW5jZShhM19tb2RlbCkgfD4gc2VsZWN0KHIuc3F1YXJlZCwgc2lnbWEsIG5vYnMpCmBgYAoKIyMjIFByZWRpY3Rpb24gRXF1YXRpb24KYGBge3J9CmV4dHJhY3RfZXEoYTNfbW9kZWwsIHVzZV9jb2VmcyA9IFRSVUUsIG9wZXJhdG9yX2xvY2F0aW9uID0gInN0YXJ0IiwKICAgICAgICAgICB3cmFwID0gVFJVRSwgY29lZl9kaWdpdHMgPSAyLCAgdGVybXNfcGVyX2xpbmUgPSAxKQpgYGAKClRoZSBwcmVkaWN0aW9uIGVxdWF0aW9uIGZyb20gdGhlIG1vZGVsIGlzIGRpYWJldGVzX3ByZXZhbGVuY2UgPSAxNC41OCAtIDAuMDYobWVkaWFuX2luY29tZSkgKyAzLjY4KHN0YXRlJF97QVp9JCkgKyA0LjQ1KHN0YXRlJF97R0F9JCkgLSA0LjczKHN0YXRlJF97TUF9JCkgLSAxLjY5KHN0YXRlJF97V0F9JCkgLSAwLjA2KG1lZGlhbl9pbmNvbWUgKiBzdGF0ZSRfe0FafSQpIC0gMC4wNShtZWRpYW5faW5jb21lICogc3RhdGUkX3tHQX0kKSArIDAuMDQobWVkaWFuX2luY29tZSAqIHN0YXRlJF97TUF9JCkgKyAwLjAxKG1lZGlhbl9pbmNvbWUgKiBzdGF0ZSRfe1dBfSQpLiBCZWNhdXNlIHRoZXJlIGlzIGFuIGludGVyYWN0aW9uIHRlcm0sIHRoZSBzbG9wZSB1c2VkIHRvIGdldCB0aGUgZml0dGVkIGRpYWJldGVzIHByZXZhbGVuY2UgdmFsdWUgaXMgZGVwZW5kZW50IG9uIGJvdGggdGhlIGNvdW50eSdzIHN0YXRlIGFuZCBtZWRpYW4gaW5jb21lLiBUaGlzIG1lYW5zIHRoZSBmaXR0ZWQgZGlhYmV0ZXMgcHJldmFsZW5jZSBvZiBhIGNvdW50eSBpbiBPaGlvIGlzIDE0LjU4IC0gMC4wNihtZWRpYW4gaW5jb21lKS4gVGhlcmUgaXNuJ3QgYW4gaW50ZXJhY3Rpb24gdGVybSAobWVkaWFuIGluY29tZSAqIHN0YXRlKSBiZWNhdXNlIE9oaW8gaGFzIGJlZW4gc2V0IGFzIHRoZSBiYXNlbGluZSBzdGF0ZSBmb3IgdGhlIG1vZGVsLiBGb3IgQXJpem9uYSwgdGhlIHByZWRpY3RlZCBwcmV2YWxlbmNlIGlzIDE0LjU4IC0gMC4wNihtZWRpYW5faW5jb21lKSArIDMuNjgoc3RhdGUkX3tBWn0kKS4gRm9yIEdlb3JnaWEsIHRoZSBwcmVkaWN0ZWQgcHJldmFsZW5jZSBpcyAxNC41OCAtIDAuMDYobWVkaWFuX2luY29tZSkgKyA0LjQ1KHN0YXRlJF97R0F9JCkuIEZvciBNYXNzYWNodXNldHRzLCB0aGUgcHJlZGljdGVkIHByZXZhbGVuY2UgaXMgMTQuNTggLSAwLjA2KG1lZGlhbl9pbmNvbWUpICsgNC43MyhzdGF0ZSRfe01BfSQpLiBGb3IgV2FzaGluZ3RvbiwgdGhlIHByZWRpY3RlZCBwcmV2YWxlbmNlIGlzIDE0LjU4IC0gMC4wNihtZWRpYW5faW5jb21lKSArIDAuMDEobWVkaWFuX2luY29tZSAqIHN0YXRlJF97V0F9JCkuCgojIyMgTW9kZWwgQ29lZmZpY2llbnRzCgpgYGB7cn0KdGlkeShhM19tb2RlbCwgY29uZi5pbnQgPSBUUlVFLCBjb25mLmxldmVsID0gMC45MCkgfD4gCiAgc2VsZWN0KHRlcm0sIGVzdGltYXRlLCBjb25mLmxvdywgY29uZi5oaWdoKSB8PgogIGtibChkaWdpdHMgPSAyKQpgYGAKCiMjIyBTdW1tYXJpZXMgb2YgTW9kZWwgRml0CgogJFJeMiQgICBSZXNpZHVhbCBTdGFuZGFyZCBFcnJvciAgIE51bWJlciBvZiBGaXR0ZWQgT2JzZXJ2YXRpb25zCi0tLS0tLS0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAwLjc0MCAgICAgICAgICAgMS4yMSAgICAgICAgICAgICAgICAgICAgICAgICAgMzE1CgoKIyMgUmVzaWR1YWwgQW5hbHlzaXMKCiMjIyBSZXNpZHVhbCBQbG90cwoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0KYTNfYXVnIDwtIGF1Z21lbnQoYTNfbW9kZWwsIG5ld2RhdGEgPSBhM19kYXRhKQoKcDEgPC0gZ2dwbG90KGEzX2F1ZywgYWVzKHggPSAuZml0dGVkLCB5ID0gLnJlc2lkKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gInJlZCIsIHNlID0gRkFMU0UpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgY29sID0gImJsdWUiLCBzZSA9IEZBTFNFKSArCiAgbGFicyh0aXRsZSA9ICJSZXNpZHVhbHMgdnMuIEZpdHRlZCBWYWx1ZXMiLCAKICAgICAgIHggPSAiRml0dGVkIGRpYWJldGVzX3ByZXZhbGVuY2UgVmFsdWVzIiwgeSA9ICJSZXNpZHVhbHMiKQoKcDIgPC0gZ2dwbG90KGEzX2F1ZywgYWVzKHNhbXBsZSA9IC5yZXNpZCkpICsKICBnZW9tX3FxKGNvbCA9ICJibGFjayIpICsgCiAgZ2VvbV9xcV9saW5lKGNvbCA9ICJyZWQiKSArIAogIGxhYnModGl0bGUgPSAiTm9ybWFsIFEtUTogTW9kZWwgUmVzaWR1YWxzIikKCnAxIC8gcDIKYGBgCgpPdmVyYWxsLCBpdCBsb29rcyBsaWtlIHRoZSBwcmVkaWN0ZWQgZGlhYmV0ZXMgcHJldmFsZW5jZSB2YWx1ZXMgZm9yIG91dGxpZXIgY291bnRpZXMgaGF2ZSBhY3R1YWxseSBiZWNvbWUgbW9yZSBleHRyZW1lIGFuZCBmYXJ0aGVyIGF3YXkgZnJvbSB0aGUgYWN0dWFsIHZhbHVlcyByZWxhdGl2ZSB0byBhbmFseXNpcyAxLiBBbHRob3VnaCB0aGUgbG9lc3Mgc21vb3RoIGN1cnZlIGxvb2tzIGxlc3MgZXh0cmVtZSB0aGFuIGluIGFuYWx5c2lzIDEsIGl0IGFjdHVhbGx5IGlzIHRoZSBzYW1lIGlmIG5vdCBtb3JlIGN1cnZlZCBhbmQgaXQganVzdCBhcHBlYXJzIGxlc3MgYmVjYXVzZSB0aGUgeS1heGlzIHJhbmdlIGlzIGxhcmdlci4gRm9yIHRoZSBtYWpvcml0eSBvZiBjb3VudGllcyB0aG91Z2gsIGl0IGFwcGVhcnMgdGhhdCB0aGUgYW5hbHlzaXMgMyBtb2RlbCBmaXRzIG11Y2ggYmV0dGVyLiBUaGlzIGlzIGV2aWRlbnQgdGhyb3VnaCB0aGUgZmlyc3QgcGxvdCwgd2hlcmUgeW91IGNhbiBzZWUgYSBsb3QgbW9yZSBvZiB0aGUgcG9pbnRzIGFyZSBjbG9zZXIgdG8gdGhlIGxpbmUgb2YgYmVzdCBmaXQsIHdoaWNoIG1lYW5zIHRoYXQgdGhlIGZpdHRlZCB2YWx1ZXMgYXJlIHZlcnkgY2xvc2UgdG8gdGhlIGFjdHVhbCBvbmVzLiBJdCBjYW4gYWxzbyBiZSBzZWVuIGluIHRoZSBRUSBwbG90LCB3aGVyZSBsb3RzIG9mIHRoZSBwb2ludHMgaW4gdGhlIG1pZGRsZSBhcmUgcHJldHR5IG11Y2ggb24gdGhlIG5vcm1hbCBRUSBsaW5lLiBXaGlsZSBpdCBsb29rcyBsaWtlIG92ZXJhbGwsIHRoZSBtb2RlbCBoYXMgYmVjb21lIG1vcmUgYWNjdXJhdGUgYnkgYWNjb3VudGluZyBmb3IgdGhlIGNvdW50eSdzIHN0YXRlLCB0aGUgcmVzaWR1YWwgdmFyaWFuY2UgYXBwZWFycyB0byBoYXZlIGluY3JlYXNlZC4gVGhpcyBjYW4gYmUgc2VlbiBpbiB0aGUgZmlyc3QgcGxvdCBhcyB0aGUgdmFyaWFuY2UgaW5jcmVhc2VzIGFzIHRoZSBmaXR0ZWQgdmFsdWUgaW5jcmVhc2VzLiBTaW1pbGFybHkgaW4gdGhlIHNlY29uZCBwbG90LCB0aGUgb3V0bGllcnMgb24gdGhlIHRhaWxzIGFyZSBmYXJ0aGVyIGF3YXkgZnJvbSB0aGUgUVEgbGluZSB3aGljaCBtZWFucyB0aGF0IHRoZSBvdXRsaWVyIHJlc2lkdWFsIHZhbHVlcyBhcmUgbGFyZ2VyLgoKIyMjIEN1eWFob2dhIENvdW50eSBDb21wYXJpc29uCgpgYGB7cn0KIyBnZXQgaW5jb21lIGFuZCBkaWFiZXRlcyB2YWx1ZXMKY3V5YWhvZ2EgPC0gY2hyXzIwMjIgfD4gZmlsdGVyKHN0YXRlID09ICJPSCIpIHw+CiAgZmlsdGVyKGNvdW50eSA9PSAiQ3V5YWhvZ2EgQ291bnR5IikgfD4KICBzZWxlY3Qoc3RhdGUsIG1lZGlhbl9pbmNvbWUsIGRpYWJldGVzX3ByZXZhbGVuY2UpCgojIHByZWRpY3Qgd2l0aCBtb2RlbApjdXlhaG9nYV9wcmVkaWN0aW9uIDwtIGF1Z21lbnQoYTNfbW9kZWwsIG5ld2RhdGEgPSBjdXlhaG9nYSkKZml0dGVkX2RpYWJldGVzIDwtIGN1eWFob2dhX3ByZWRpY3Rpb24kLmZpdHRlZAoKZ2x1ZSgiQ3V5YWhvZ2EgQWN0dWFsOiB7Y3V5YWhvZ2EkZGlhYmV0ZXNfcHJldmFsZW5jZX0lCkN1eWFob2dhIFByZWRpY3RlZDoge3JvdW5kKGZpdHRlZF9kaWFiZXRlcywgMil9JSIpCmBgYAoKIyMjIExhcmdlc3QgUmVzaWR1YWwgQ291bnRpZXMKCmBgYHtyfQojIGdldCBwcmVkaWN0ZWQgdmFsdWVzIGZvciBhbGwgY291bnRpZXMKcGxvdChhM19tb2RlbCwgd2hpY2ggPSBjKDE6MikpCgojIHByaW50IGNvdW50aWVzIGluIG9yZGVyIG9mIHJlc2lkdWFsIG1hZ25pdHVkZQppbmRpY2VzIDwtIGMoMjc3LCAxNDMpCmZvciAoaW5kZXggaW4gaW5kaWNlcykgewogICMgb3JpZ2luYWwgZGF0YQogIHByaW50KGNocl8yMDIyW2luZGV4LCBdIHw+IHNlbGVjdChjb3VudHksIHN0YXRlLCBtZWRpYW5faW5jb21lLCBkaWFiZXRlc19wcmV2YWxlbmNlKSkKICAjIHJlc2lkdWFsIHZhbHVlCiAgcHJpbnQoYTNfYXVnW2luZGV4LCBdIHw+IHNlbGVjdChtZWRpYW5faW5jb21lLCBkaWFiZXRlc19wcmV2YWxlbmNlLCAuZml0dGVkLCAucmVzaWQpKQp9CmBgYAoKVGhlIGNvdW50eSB3aXRoIHRoZSBsYXJnZXN0IGFic29sdXRlIHZhbHVlIHJlc2lkdWFsIGlzIEFkYW1zIENvdW50eSwgV0EgKDQuNzEpIGFuZCB0aGUgY291bnR5IHdpdGggdGhlIHNlY29uZCBsYXJnZXN0IGFic29sdXRlIHZhbHVlIHJlc2lkdWFsIGlzIFN0ZXdhcnQgQ291bnR5LCBHQSAoNC4yMSkuCgojIyBDb25jbHVzaW9ucyBhbmQgTGltaXRhdGlvbnMKCkluIGFuYWx5c2lzIDMsIHdlIHdhbnRlZCB0byBpbnZlc3RpZ2F0ZSBpZiBhIGNvdW50eSdzIHN0YXRlIGludGVyYWN0aW5nIHdpdGggdGhlaXIgbWVkaWFuIGluY29tZSBoZWxwZWQgYmVjb21lIGEgYmV0dGVyIHByZWRpY3RvciBvZiB0aGVpciBkaWFiZXRlcyBwcmV2YWxlbmNlLiBCYXNlZCBvbiBvdXIgZmlyc3QgYW5hbHlzaXMgbW9kZWwgdXNpbmcgb25seSBtZWRpYW4gaW5jb21lIHRvIHByZWRpY3QgZGlhYmV0ZXMgcHJldmFsZW5jZSwgdGhlICRSXjIkIHZhbHVlIHdhcyAwLjU4NSBhbmQgcmVzaWR1YWwgc3RhbmRhcmQgZXJyb3Igd2FzIDAuMTI4LiBJbiB0aGlzIG1vZGVsIHdpdGggYWxzbyBpbmNsdWRpbmcgdGhlIGNvdW50eSdzIHN0YXRlLCB0aGUgJFJeMiQgdmFsdWUgaXMgMC43NDAgYW5kIHJlc2lkdWFsIHN0YW5kYXJkIGVycm9yIGlzIDEuMjEwLiAkUl4yJCByZXByZXNlbnRzIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBkaWFiZXRlcyBwcmV2YWxlbmNlIHZhcmlhbmNlIGV4cGxhaW5lZCBieSByZWdyZXNzaW9uIG1vZGVsIHZhcmlhYmxlcy4gV2l0aCB0aGF0LCBhIGhpZ2hlciB2YWx1ZSBpcyBiZXR0ZXIsIGFzIGl0IG1lYW5zIHRoZSByZWxhdGlvbnNoaXAgaW4gdGhlIG1vZGVsIGJldHdlZW4gcHJlZGljdG9yIGFuZCBvdXRjb21lIHZhcmlhYmxlcyBpcyBzdHJvbmdlci4gR2l2ZW4gdGhhdCB0aGUgJFJeMiQgdmFsdWUgb2YgdGhpcyBtb2RlbCBpcyAwLjE1NSBoaWdoZXIgYW5kIHRoZSByZXNpZHVhbCBzdGFuZGFyZCBlcnJvciBpcyAwLjAwNyBsb3dlciwgd2UgY2FuIGRldGVybWluZSB0aGF0IGFkZGluZyBzdGF0ZSBhcyBhbiBpbnRlcmFjdGlvbiB0ZXJtIHdpdGggbWVkaWFuIGluY29tZSBoZWxwcyB0byBwcmVkaWN0IGEgY291bnR5J3MgZGlhYmV0ZXMgcHJldmFsZW5jZSBtb3JlIGFjY3VyYXRlbHkuIFRvIGZ1cnRoZXIgdGhpcyBpZGVhLCB3ZSB3aWxsIHRha2UgYSByYW5kb20gc2FtcGxlIG9mIDUwIGluZGljZXMgb2YgdGhlIGRhdGEgYW5kIHNlZSB3aGljaCBtb2RlbCAoMSBvciAzKSBwZXJmb3JtZWQgYmV0dGVyIGluIHRlcm1zIG9mIGFic29sdXRlIHJlc2lkdWFsIHZhbHVlLgoKYGBge3J9CiMgc2V0IHNlZWQgZm9yIHJlcHJvZHVjYWJsZSByZXN1bHRzCnNldC5zZWVkKDEyMzQ1KQoKIyBjcmVhdGUgZW1wdHkgcmVzdWx0cyB0YWJsZQpyZXN1bHRzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2wgPSA0LCBucm93ID0gMCkpCmNvbG5hbWVzKHJlc3VsdHMpIDwtIGMoJ0FjdHVhbCcsICdNMSBGaXR0ZWQnLCAnTTMgRml0dGVkJywgJ0JldHRlciBGaXR0ZWQnKQoKIyBjcmVhdGUgcmFuZG9tIGluZGV4IHZhbHVlcwppbmRpY2VzIDwtIHNhbXBsZSgxOjMxNSwgNTAsIHJlcGxhY2UgPSBGQUxTRSkKCiMgZ2V0IGFic29sdXRlIHJlc2lkdWFsIHZhbHVlcyBmb3IgdGhlIGluZGljZXMKZm9yIChpbmRleCBpbiBpbmRpY2VzKSB7CiAgYWN0dWFsX3ZhbHVlIDwtIGNocl8yMDIyW2luZGV4LCBdJGRpYWJldGVzX3ByZXZhbGVuY2UKICBtb2RlbDFfcmVzaWQgPC0gYWJzKGV4cChhMV9hdWdbaW5kZXgsIF0kLnJlc2lkKSkgICAgICAgICAgIyB1bnRyYW5zZm9ybSByZXNpZHVhbAogIG1vZGVsM19yZXNpZCA8LSBhYnMoYTNfYXVnW2luZGV4LCBdJC5yZXNpZCkKICAKICB3aGljaF9iZXR0ZXIgPC0gMQogIGlmIChtb2RlbDFfcmVzaWQgPiBtb2RlbDNfcmVzaWQpIHsKICAgIHdoaWNoX2JldHRlciA8LSAzCiAgfQogIAogIG5ld19yb3cgPC0gYyhhY3R1YWxfdmFsdWUsIG1vZGVsMV9yZXNpZCwgbW9kZWwzX3Jlc2lkLCB3aGljaF9iZXR0ZXIpCiAgcmVzdWx0c1tucm93KHJlc3VsdHMpICsgMSxdIDwtIG5ld19yb3cKfQoKaGVhZChyZXN1bHRzLCAxMCkKCiMgc2VlIGJyZWFrZG93biBvZiB3aGljaCBtb2RlbCBwcmVkaWN0ZWQgYSBjbG9zZXIgZGlhYmV0ZXMgcHJldmFsZW5jZSB2YWx1ZQp0YWJ5bChyZXN1bHRzJGBCZXR0ZXIgRml0dGVkYCkKYGBgCgpGcm9tIHRoaXMsIHdlIGNhbiBzZWUgdGhhdCA3MCUgb2YgdGhlIHJhbmRvbSA1MCBkYXRhIGluZGljZXMgd2VyZSBwcmVkaWN0ZWQgYmV0dGVyIGJ5IG1vZGVsIDMgdGhhbiBieSBtb2RlbCAxLiBUaGlzIGhlbHBzIGRlbW9uc3RyYXRlIGhvdyAgYSBjb3VudHkncyBzdGF0ZSBhbG9uZyB3aXRoIHRoZWlyIG1lZGlhbiBpbmNvbWUgaGVscHMgcHJlZGljdCB0aGUgZGlhYmV0ZXMgcHJldmFsZW5jZSBiZXR0ZXIgdGhhbiBqdXN0IHdpdGggdGhlIG1lZGlhbiBpbmNvbWUuCgpUaGlzIG1vZGVsIGFwcGVhcnMgdG8gd29yayBiZXN0IGluIHRlcm1zIG9mIHZhcmlvdXMgbnVtYmVycywgc3VjaCBhcyAkUl4yJCB2YWx1ZSBhbmQgcmVzaWR1YWxzIGFuZCBkb2Vzbid0IGFwcGVhciB0byBoYXZlIG1hbnkgbGltaXRhdGlvbnMgYXQgYWxsLiBPbmUgbGltaXRhdGlvbiB0aGF0IG1heSBtYWtlIHByZWRpY3Rpb25zIGEgYml0IGxlc3MgYWNjdXJhdGUgaXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBudW1iZXIgb2YgY291bnRpZXMgaW4gZWFjaCBzdGF0ZS4gU29tZSBvZiB0aGUgc3RhdGVzLCBsaWtlIEFyaXpvbmEgYW5kIE1hc3NhY2h1c2V0dHMgaGF2ZSB2ZXJ5IGZldyBjb3VudGllcyAoMTUgYW5kIDE0IHJlc3BlY3RpdmVseSksIHBhcnRpY3VsYXJseSB3aGVuIGNvbXBhcmVkIHdpdGggc3RhdGVzIGxpa2UgR2VvcmdpYSwgd2hvIGhhcyAxNTUgY291bnRpZXMuIFNpbmNlIHdlIGhhdmUgYWRkZWQgc3RhdGUgYXMgYW5vdGhlciBwcmVkaWN0b3IgdmFyaWFibGUgYW5kIGl0IGludGVyYWN0cyB3aXRoIG1lZGlhbiBpbmNvbWUsIHRoZSBzdGF0ZXMnbnVtYmVyIG9mIGNvdW50aWVzIGJlY29tZSByZWxhdmFudCBhcyB0aGV5IG1ha2UgbW9yZSBjb2VmZmljaWVudHMgaW4gdGhlIG1vZGVsLiBXaXRoIHRoYXQsIHN0YXRlcyB3aXRoIG1vcmUgY291bnRpZXMgd2lsbCBoYXZlIG1vcmUgYWNjdXJhdGUgY29lZmZpY2llbnRzIGJlY2F1c2UgdGhlcmUncyBtb3JlIGRhdGEgdG8gdHJhaW4gdGhlIG1vZGVsIG9uLCBzbyB0aGUgcHJlZGljdGVkIHZhbHVlcyBmb3IgdGhvc2Ugc3RhdGVzIHdpbGwgbGlrZWx5IGJlIG1vcmUgYWNjdXJhdGUgdGhhbiBzdGF0ZXMgd2l0aCBsZXNzIGNvdW50aWVzIChleGNsdWRpbmcgb3V0bGllcnMpLiBBbm90aGVyIHRoaW5nIHRvIGxvb2sgYXQgd291bGQgYmUgdGhlIG5vcm1hbGl0eSBvZiByZXNpZHVhbHMsIGFzIGl0IGFwcGVhcnMgdGhhdCB0aGlzIG1vZGVsIGlzbid0IGFzIHJlc2lsaWVudCB0byBvdXRsaWVyIGNvdW50aWVzLiBUaGlzIGlzIGV2aWRlbnQgdGhyb3VnaCBlYWNoIG9mIHRoZSByZXNpZHVhbCBwbG90cywgYXMgaW4gdGhlIGZpcnN0IG9uZSwgdGhlcmUncyBtb3JlIHZhcmlhdGlvbiBhcyBkaWFiZXRlcyBwcmV2YWxlbmNlIHZhbHVlcyBpbmNyZWFzZSBhbmQgaW4gdGhlIHNlY29uZCBvbmUsIHRoZSB0YWlscyBhcmUgZmFydGhlciBhd2F5IGZyb20gdGhlIFFRIGxpbmUuIEEgZmluYWwgbGltaXRhdGlvbiB3b3VsZCBiZSB0aGF0IGJ5IGxvb2tpbmcgYXQgVVMgZGlhYmV0ZXMgcHJldmFsZW5jZSBieSBzdGF0ZSwgR2VvcmdpYSBhbmQgTWFzc2FjaHVzZXR0cyBhcHBlYXIgdG8gYmUgZXh0cmVtZSBzdGF0ZXMuIFJlbGF0aXZlIHRvIHRoZSBVUyBtZWRpYW4gKDkuOCksIEdlb3JnaWEgaGFzIGEgZGlhYmV0ZXMgcHJldmFsZW5jZSBub3RpY2VhYmx5IGhpZ2hlciAoMTEuNykgd2hpbGUgTWFzc2FjaHVzZXR0cyBpcyBub3RpY2VhYmx5IGxvd2VyICg3LjcpLiBUaGUgb3RoZXIgc3RhdGVzIGFyZSBhbGwgcmVsYXRpdmVseSBjbG9zZSB0byB0aGUgbWVkaWFuIHZhbHVlLiBXaXRoIHRoaXMsIEdlb3JnaWEgYW5kIE1hc3NhY2h1c2V0dHMgbWF5IG5vdCBiZSB0aGUgYmVzdCBzdGF0ZXMgdG8gaW5jbHVkZSBpbiB0aGUgZGF0YSBhcyBpdCBkb2Vzbid0IGhlbHAgcHJlZGljdCBhbGwgVVMgY291bnRpZXMnIGRpYWJldGVzIHByZXZhbGVuY2UgYXMgd2VsbCBiZWNhdXNlIHRoZXkgYXJlIG91dGxpZXIgc3RhdGVzLiAKCgojIFNlc3Npb24gSW5mb3JtYXRpb24KClRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLgoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgoK